xibarriers.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932
  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. #ifdef HAVE_DIX_CONFIG_H
  44. #include <dix-config.h>
  45. #endif
  46. #include "xibarriers.h"
  47. #include "scrnintstr.h"
  48. #include "cursorstr.h"
  49. #include "dixevents.h"
  50. #include "servermd.h"
  51. #include "mipointer.h"
  52. #include "inputstr.h"
  53. #include "windowstr.h"
  54. #include "xace.h"
  55. #include "list.h"
  56. #include "exglobals.h"
  57. #include "eventstr.h"
  58. #include "mi.h"
  59. RESTYPE PointerBarrierType;
  60. static DevPrivateKeyRec BarrierScreenPrivateKeyRec;
  61. #define BarrierScreenPrivateKey (&BarrierScreenPrivateKeyRec)
  62. typedef struct PointerBarrierClient *PointerBarrierClientPtr;
  63. struct PointerBarrierDevice {
  64. struct xorg_list entry;
  65. int deviceid;
  66. Time last_timestamp;
  67. int barrier_event_id;
  68. int release_event_id;
  69. Bool hit;
  70. Bool seen;
  71. };
  72. struct PointerBarrierClient {
  73. XID id;
  74. ScreenPtr screen;
  75. Window window;
  76. struct PointerBarrier barrier;
  77. struct xorg_list entry;
  78. /* num_devices/device_ids are devices the barrier applies to */
  79. int num_devices;
  80. int *device_ids; /* num_devices */
  81. /* per_device keeps track of devices actually blocked by barriers */
  82. struct xorg_list per_device;
  83. };
  84. typedef struct _BarrierScreen {
  85. struct xorg_list barriers;
  86. } BarrierScreenRec, *BarrierScreenPtr;
  87. #define GetBarrierScreen(s) ((BarrierScreenPtr)dixLookupPrivate(&(s)->devPrivates, BarrierScreenPrivateKey))
  88. #define GetBarrierScreenIfSet(s) GetBarrierScreen(s)
  89. #define SetBarrierScreen(s,p) dixSetPrivate(&(s)->devPrivates, BarrierScreenPrivateKey, p)
  90. static struct PointerBarrierDevice *AllocBarrierDevice(void)
  91. {
  92. struct PointerBarrierDevice *pbd = NULL;
  93. pbd = malloc(sizeof(struct PointerBarrierDevice));
  94. if (!pbd)
  95. return NULL;
  96. pbd->deviceid = -1; /* must be set by caller */
  97. pbd->barrier_event_id = 1;
  98. pbd->release_event_id = 0;
  99. pbd->hit = FALSE;
  100. pbd->seen = FALSE;
  101. xorg_list_init(&pbd->entry);
  102. return pbd;
  103. }
  104. static void FreePointerBarrierClient(struct PointerBarrierClient *c)
  105. {
  106. struct PointerBarrierDevice *pbd = NULL, *tmp = NULL;
  107. xorg_list_for_each_entry_safe(pbd, tmp, &c->per_device, entry) {
  108. free(pbd);
  109. }
  110. free(c);
  111. }
  112. static struct PointerBarrierDevice *GetBarrierDevice(struct PointerBarrierClient *c, int deviceid)
  113. {
  114. struct PointerBarrierDevice *pbd = NULL;
  115. xorg_list_for_each_entry(pbd, &c->per_device, entry) {
  116. if (pbd->deviceid == deviceid)
  117. break;
  118. }
  119. BUG_WARN(!pbd);
  120. return pbd;
  121. }
  122. static BOOL
  123. barrier_is_horizontal(const struct PointerBarrier *barrier)
  124. {
  125. return barrier->y1 == barrier->y2;
  126. }
  127. static BOOL
  128. barrier_is_vertical(const struct PointerBarrier *barrier)
  129. {
  130. return barrier->x1 == barrier->x2;
  131. }
  132. /**
  133. * @return The set of barrier movement directions the movement vector
  134. * x1/y1 → x2/y2 represents.
  135. */
  136. int
  137. barrier_get_direction(int x1, int y1, int x2, int y2)
  138. {
  139. int direction = 0;
  140. /* which way are we trying to go */
  141. if (x2 > x1)
  142. direction |= BarrierPositiveX;
  143. if (x2 < x1)
  144. direction |= BarrierNegativeX;
  145. if (y2 > y1)
  146. direction |= BarrierPositiveY;
  147. if (y2 < y1)
  148. direction |= BarrierNegativeY;
  149. return direction;
  150. }
  151. /**
  152. * Test if the barrier may block movement in the direction defined by
  153. * x1/y1 → x2/y2. This function only tests whether the directions could be
  154. * blocked, it does not test if the barrier actually blocks the movement.
  155. *
  156. * @return TRUE if the barrier blocks the direction of movement or FALSE
  157. * otherwise.
  158. */
  159. BOOL
  160. barrier_is_blocking_direction(const struct PointerBarrier * barrier,
  161. int direction)
  162. {
  163. /* Barriers define which way is ok, not which way is blocking */
  164. return (barrier->directions & direction) != direction;
  165. }
  166. static BOOL
  167. inside_segment(int v, int v1, int v2)
  168. {
  169. if (v1 < 0 && v2 < 0) /* line */
  170. return TRUE;
  171. else if (v1 < 0) /* ray */
  172. return v <= v2;
  173. else if (v2 < 0) /* ray */
  174. return v >= v1;
  175. else /* line segment */
  176. return v >= v1 && v <= v2;
  177. }
  178. #define T(v, a, b) (((float)v) - (a)) / ((b) - (a))
  179. #define F(t, a, b) ((t) * ((a) - (b)) + (a))
  180. /**
  181. * Test if the movement vector x1/y1 → x2/y2 is intersecting with the
  182. * barrier. A movement vector with the startpoint or endpoint adjacent to
  183. * the barrier itself counts as intersecting.
  184. *
  185. * @param x1 X start coordinate of movement vector
  186. * @param y1 Y start coordinate of movement vector
  187. * @param x2 X end coordinate of movement vector
  188. * @param y2 Y end coordinate of movement vector
  189. * @param[out] distance The distance between the start point and the
  190. * intersection with the barrier (if applicable).
  191. * @return TRUE if the barrier intersects with the given vector
  192. */
  193. BOOL
  194. barrier_is_blocking(const struct PointerBarrier * barrier,
  195. int x1, int y1, int x2, int y2, double *distance)
  196. {
  197. if (barrier_is_vertical(barrier)) {
  198. float t, y;
  199. t = T(barrier->x1, x1, x2);
  200. if (t < 0 || t > 1)
  201. return FALSE;
  202. /* Edge case: moving away from barrier. */
  203. if (x2 > x1 && t == 0)
  204. return FALSE;
  205. y = F(t, y1, y2);
  206. if (!inside_segment(y, barrier->y1, barrier->y2))
  207. return FALSE;
  208. *distance = sqrt((pow(y - y1, 2) + pow(barrier->x1 - x1, 2)));
  209. return TRUE;
  210. }
  211. else {
  212. float t, x;
  213. t = T(barrier->y1, y1, y2);
  214. if (t < 0 || t > 1)
  215. return FALSE;
  216. /* Edge case: moving away from barrier. */
  217. if (y2 > y1 && t == 0)
  218. return FALSE;
  219. x = F(t, x1, x2);
  220. if (!inside_segment(x, barrier->x1, barrier->x2))
  221. return FALSE;
  222. *distance = sqrt((pow(x - x1, 2) + pow(barrier->y1 - y1, 2)));
  223. return TRUE;
  224. }
  225. }
  226. #define HIT_EDGE_EXTENTS 2
  227. static BOOL
  228. barrier_inside_hit_box(struct PointerBarrier *barrier, int x, int y)
  229. {
  230. int x1, x2, y1, y2;
  231. int dir;
  232. x1 = barrier->x1;
  233. x2 = barrier->x2;
  234. y1 = barrier->y1;
  235. y2 = barrier->y2;
  236. dir = ~(barrier->directions);
  237. if (barrier_is_vertical(barrier)) {
  238. if (dir & BarrierPositiveX)
  239. x1 -= HIT_EDGE_EXTENTS;
  240. if (dir & BarrierNegativeX)
  241. x2 += HIT_EDGE_EXTENTS;
  242. }
  243. if (barrier_is_horizontal(barrier)) {
  244. if (dir & BarrierPositiveY)
  245. y1 -= HIT_EDGE_EXTENTS;
  246. if (dir & BarrierNegativeY)
  247. y2 += HIT_EDGE_EXTENTS;
  248. }
  249. return x >= x1 && x <= x2 && y >= y1 && y <= y2;
  250. }
  251. static BOOL
  252. barrier_blocks_device(struct PointerBarrierClient *client,
  253. DeviceIntPtr dev)
  254. {
  255. int i;
  256. int master_id;
  257. /* Clients with no devices are treated as
  258. * if they specified XIAllDevices. */
  259. if (client->num_devices == 0)
  260. return TRUE;
  261. master_id = GetMaster(dev, POINTER_OR_FLOAT)->id;
  262. for (i = 0; i < client->num_devices; i++) {
  263. int device_id = client->device_ids[i];
  264. if (device_id == XIAllDevices ||
  265. device_id == XIAllMasterDevices ||
  266. device_id == master_id)
  267. return TRUE;
  268. }
  269. return FALSE;
  270. }
  271. /**
  272. * Find the nearest barrier client that is blocking movement from x1/y1 to x2/y2.
  273. *
  274. * @param dir Only barriers blocking movement in direction dir are checked
  275. * @param x1 X start coordinate of movement vector
  276. * @param y1 Y start coordinate of movement vector
  277. * @param x2 X end coordinate of movement vector
  278. * @param y2 Y end coordinate of movement vector
  279. * @return The barrier nearest to the movement origin that blocks this movement.
  280. */
  281. static struct PointerBarrierClient *
  282. barrier_find_nearest(BarrierScreenPtr cs, DeviceIntPtr dev,
  283. int dir,
  284. int x1, int y1, int x2, int y2)
  285. {
  286. struct PointerBarrierClient *c, *nearest = NULL;
  287. double min_distance = INT_MAX; /* can't get higher than that in X anyway */
  288. xorg_list_for_each_entry(c, &cs->barriers, entry) {
  289. struct PointerBarrier *b = &c->barrier;
  290. struct PointerBarrierDevice *pbd;
  291. double distance;
  292. pbd = GetBarrierDevice(c, dev->id);
  293. if (pbd->seen)
  294. continue;
  295. if (!barrier_is_blocking_direction(b, dir))
  296. continue;
  297. if (!barrier_blocks_device(c, dev))
  298. continue;
  299. if (barrier_is_blocking(b, x1, y1, x2, y2, &distance)) {
  300. if (min_distance > distance) {
  301. min_distance = distance;
  302. nearest = c;
  303. }
  304. }
  305. }
  306. return nearest;
  307. }
  308. /**
  309. * Clamp to the given barrier given the movement direction specified in dir.
  310. *
  311. * @param barrier The barrier to clamp to
  312. * @param dir The movement direction
  313. * @param[out] x The clamped x coordinate.
  314. * @param[out] y The clamped x coordinate.
  315. */
  316. void
  317. barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x,
  318. int *y)
  319. {
  320. if (barrier_is_vertical(barrier)) {
  321. if ((dir & BarrierNegativeX) & ~barrier->directions)
  322. *x = barrier->x1;
  323. if ((dir & BarrierPositiveX) & ~barrier->directions)
  324. *x = barrier->x1 - 1;
  325. }
  326. if (barrier_is_horizontal(barrier)) {
  327. if ((dir & BarrierNegativeY) & ~barrier->directions)
  328. *y = barrier->y1;
  329. if ((dir & BarrierPositiveY) & ~barrier->directions)
  330. *y = barrier->y1 - 1;
  331. }
  332. }
  333. void
  334. input_constrain_cursor(DeviceIntPtr dev, ScreenPtr screen,
  335. int current_x, int current_y,
  336. int dest_x, int dest_y,
  337. int *out_x, int *out_y,
  338. int *nevents, InternalEvent* events)
  339. {
  340. /* Clamped coordinates here refer to screen edge clamping. */
  341. BarrierScreenPtr cs = GetBarrierScreen(screen);
  342. int x = dest_x,
  343. y = dest_y;
  344. int dir;
  345. struct PointerBarrier *nearest = NULL;
  346. PointerBarrierClientPtr c;
  347. Time ms = GetTimeInMillis();
  348. BarrierEvent ev = {
  349. .header = ET_Internal,
  350. .type = 0,
  351. .length = sizeof (BarrierEvent),
  352. .time = ms,
  353. .deviceid = dev->id,
  354. .sourceid = dev->id,
  355. .dx = dest_x - current_x,
  356. .dy = dest_y - current_y,
  357. .root = screen->root->drawable.id,
  358. };
  359. InternalEvent *barrier_events = events;
  360. DeviceIntPtr master;
  361. if (nevents)
  362. *nevents = 0;
  363. if (xorg_list_is_empty(&cs->barriers) || IsFloating(dev))
  364. goto out;
  365. /**
  366. * This function is only called for slave devices, but pointer-barriers
  367. * are for master-devices only. Flip the device to the master here,
  368. * continue with that.
  369. */
  370. master = GetMaster(dev, MASTER_POINTER);
  371. /* How this works:
  372. * Given the origin and the movement vector, get the nearest barrier
  373. * to the origin that is blocking the movement.
  374. * Clamp to that barrier.
  375. * Then, check from the clamped intersection to the original
  376. * destination, again finding the nearest barrier and clamping.
  377. */
  378. dir = barrier_get_direction(current_x, current_y, x, y);
  379. while (dir != 0) {
  380. int new_sequence;
  381. struct PointerBarrierDevice *pbd;
  382. c = barrier_find_nearest(cs, master, dir, current_x, current_y, x, y);
  383. if (!c)
  384. break;
  385. nearest = &c->barrier;
  386. pbd = GetBarrierDevice(c, master->id);
  387. new_sequence = !pbd->hit;
  388. pbd->seen = TRUE;
  389. pbd->hit = TRUE;
  390. if (pbd->barrier_event_id == pbd->release_event_id)
  391. continue;
  392. ev.type = ET_BarrierHit;
  393. barrier_clamp_to_barrier(nearest, dir, &x, &y);
  394. if (barrier_is_vertical(nearest)) {
  395. dir &= ~(BarrierNegativeX | BarrierPositiveX);
  396. current_x = x;
  397. }
  398. else if (barrier_is_horizontal(nearest)) {
  399. dir &= ~(BarrierNegativeY | BarrierPositiveY);
  400. current_y = y;
  401. }
  402. ev.flags = 0;
  403. ev.event_id = pbd->barrier_event_id;
  404. ev.barrierid = c->id;
  405. ev.dt = new_sequence ? 0 : ms - pbd->last_timestamp;
  406. ev.window = c->window;
  407. pbd->last_timestamp = ms;
  408. /* root x/y is filled in later */
  409. barrier_events->barrier_event = ev;
  410. barrier_events++;
  411. *nevents += 1;
  412. }
  413. xorg_list_for_each_entry(c, &cs->barriers, entry) {
  414. struct PointerBarrierDevice *pbd;
  415. int flags = 0;
  416. pbd = GetBarrierDevice(c, master->id);
  417. pbd->seen = FALSE;
  418. if (!pbd->hit)
  419. continue;
  420. if (barrier_inside_hit_box(&c->barrier, x, y))
  421. continue;
  422. pbd->hit = FALSE;
  423. ev.type = ET_BarrierLeave;
  424. if (pbd->barrier_event_id == pbd->release_event_id)
  425. flags |= XIBarrierPointerReleased;
  426. ev.flags = flags;
  427. ev.event_id = pbd->barrier_event_id;
  428. ev.barrierid = c->id;
  429. ev.dt = ms - pbd->last_timestamp;
  430. ev.window = c->window;
  431. pbd->last_timestamp = ms;
  432. /* root x/y is filled in later */
  433. barrier_events->barrier_event = ev;
  434. barrier_events++;
  435. *nevents += 1;
  436. /* If we've left the hit box, this is the
  437. * start of a new event ID. */
  438. pbd->barrier_event_id++;
  439. }
  440. out:
  441. *out_x = x;
  442. *out_y = y;
  443. }
  444. static void
  445. sort_min_max(INT16 *a, INT16 *b)
  446. {
  447. INT16 A, B;
  448. if (*a < 0 || *b < 0)
  449. return;
  450. A = *a;
  451. B = *b;
  452. *a = min(A, B);
  453. *b = max(A, B);
  454. }
  455. static int
  456. CreatePointerBarrierClient(ClientPtr client,
  457. xXFixesCreatePointerBarrierReq * stuff,
  458. PointerBarrierClientPtr *client_out)
  459. {
  460. WindowPtr pWin;
  461. ScreenPtr screen;
  462. BarrierScreenPtr cs;
  463. int err;
  464. int size;
  465. int i;
  466. struct PointerBarrierClient *ret;
  467. CARD16 *in_devices;
  468. DeviceIntPtr dev;
  469. size = sizeof(*ret) + sizeof(DeviceIntPtr) * stuff->num_devices;
  470. ret = malloc(size);
  471. if (!ret) {
  472. return BadAlloc;
  473. }
  474. xorg_list_init(&ret->per_device);
  475. err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess);
  476. if (err != Success) {
  477. client->errorValue = stuff->window;
  478. goto error;
  479. }
  480. screen = pWin->drawable.pScreen;
  481. cs = GetBarrierScreen(screen);
  482. ret->screen = screen;
  483. ret->window = stuff->window;
  484. ret->num_devices = stuff->num_devices;
  485. if (ret->num_devices > 0)
  486. ret->device_ids = (int*)&ret[1];
  487. else
  488. ret->device_ids = NULL;
  489. in_devices = (CARD16 *) &stuff[1];
  490. for (i = 0; i < stuff->num_devices; i++) {
  491. int device_id = in_devices[i];
  492. DeviceIntPtr device;
  493. if ((err = dixLookupDevice (&device, device_id,
  494. client, DixReadAccess))) {
  495. client->errorValue = device_id;
  496. goto error;
  497. }
  498. if (!IsMaster (device)) {
  499. client->errorValue = device_id;
  500. err = BadDevice;
  501. goto error;
  502. }
  503. ret->device_ids[i] = device_id;
  504. }
  505. /* Alloc one per master pointer, they're the ones that can be blocked */
  506. xorg_list_init(&ret->per_device);
  507. nt_list_for_each_entry(dev, inputInfo.devices, next) {
  508. struct PointerBarrierDevice *pbd;
  509. if (dev->type != MASTER_POINTER)
  510. continue;
  511. pbd = AllocBarrierDevice();
  512. if (!pbd) {
  513. err = BadAlloc;
  514. goto error;
  515. }
  516. pbd->deviceid = dev->id;
  517. xorg_list_add(&pbd->entry, &ret->per_device);
  518. }
  519. ret->id = stuff->barrier;
  520. ret->barrier.x1 = stuff->x1;
  521. ret->barrier.x2 = stuff->x2;
  522. ret->barrier.y1 = stuff->y1;
  523. ret->barrier.y2 = stuff->y2;
  524. sort_min_max(&ret->barrier.x1, &ret->barrier.x2);
  525. sort_min_max(&ret->barrier.y1, &ret->barrier.y2);
  526. ret->barrier.directions = stuff->directions & 0x0f;
  527. if (barrier_is_horizontal(&ret->barrier))
  528. ret->barrier.directions &= ~(BarrierPositiveX | BarrierNegativeX);
  529. if (barrier_is_vertical(&ret->barrier))
  530. ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY);
  531. xorg_list_add(&ret->entry, &cs->barriers);
  532. *client_out = ret;
  533. return Success;
  534. error:
  535. *client_out = NULL;
  536. FreePointerBarrierClient(ret);
  537. return err;
  538. }
  539. static int
  540. BarrierFreeBarrier(void *data, XID id)
  541. {
  542. struct PointerBarrierClient *c;
  543. Time ms = GetTimeInMillis();
  544. DeviceIntPtr dev = NULL;
  545. ScreenPtr screen;
  546. c = container_of(data, struct PointerBarrierClient, barrier);
  547. screen = c->screen;
  548. for (dev = inputInfo.devices; dev; dev = dev->next) {
  549. struct PointerBarrierDevice *pbd;
  550. int root_x, root_y;
  551. BarrierEvent ev = {
  552. .header = ET_Internal,
  553. .type = ET_BarrierLeave,
  554. .length = sizeof (BarrierEvent),
  555. .time = ms,
  556. /* .deviceid */
  557. .sourceid = 0,
  558. .barrierid = c->id,
  559. .window = c->window,
  560. .root = screen->root->drawable.id,
  561. .dx = 0,
  562. .dy = 0,
  563. /* .root_x */
  564. /* .root_y */
  565. /* .dt */
  566. /* .event_id */
  567. .flags = XIBarrierPointerReleased,
  568. };
  569. if (dev->type != MASTER_POINTER)
  570. continue;
  571. pbd = GetBarrierDevice(c, dev->id);
  572. if (!pbd->hit)
  573. continue;
  574. ev.deviceid = dev->id;
  575. ev.event_id = pbd->barrier_event_id;
  576. ev.dt = ms - pbd->last_timestamp;
  577. GetSpritePosition(dev, &root_x, &root_y);
  578. ev.root_x = root_x;
  579. ev.root_y = root_y;
  580. mieqEnqueue(dev, (InternalEvent *) &ev);
  581. }
  582. xorg_list_del(&c->entry);
  583. FreePointerBarrierClient(c);
  584. return Success;
  585. }
  586. static void add_master_func(void *res, XID id, void *devid)
  587. {
  588. struct PointerBarrier *b;
  589. struct PointerBarrierClient *barrier;
  590. struct PointerBarrierDevice *pbd;
  591. int *deviceid = devid;
  592. b = res;
  593. barrier = container_of(b, struct PointerBarrierClient, barrier);
  594. pbd = AllocBarrierDevice();
  595. pbd->deviceid = *deviceid;
  596. xorg_list_add(&pbd->entry, &barrier->per_device);
  597. }
  598. static void remove_master_func(void *res, XID id, void *devid)
  599. {
  600. struct PointerBarrierDevice *pbd;
  601. struct PointerBarrierClient *barrier;
  602. struct PointerBarrier *b;
  603. DeviceIntPtr dev;
  604. int *deviceid = devid;
  605. int rc;
  606. Time ms = GetTimeInMillis();
  607. rc = dixLookupDevice(&dev, *deviceid, serverClient, DixSendAccess);
  608. if (rc != Success)
  609. return;
  610. b = res;
  611. barrier = container_of(b, struct PointerBarrierClient, barrier);
  612. pbd = GetBarrierDevice(barrier, *deviceid);
  613. if (pbd->hit) {
  614. BarrierEvent ev = {
  615. .header = ET_Internal,
  616. .type =ET_BarrierLeave,
  617. .length = sizeof (BarrierEvent),
  618. .time = ms,
  619. .deviceid = *deviceid,
  620. .sourceid = 0,
  621. .dx = 0,
  622. .dy = 0,
  623. .root = barrier->screen->root->drawable.id,
  624. .window = barrier->window,
  625. .dt = ms - pbd->last_timestamp,
  626. .flags = XIBarrierPointerReleased,
  627. .event_id = pbd->barrier_event_id,
  628. .barrierid = barrier->id,
  629. };
  630. mieqEnqueue(dev, (InternalEvent *) &ev);
  631. }
  632. xorg_list_del(&pbd->entry);
  633. free(pbd);
  634. }
  635. void XIBarrierNewMasterDevice(ClientPtr client, int deviceid)
  636. {
  637. FindClientResourcesByType(client, PointerBarrierType, add_master_func, &deviceid);
  638. }
  639. void XIBarrierRemoveMasterDevice(ClientPtr client, int deviceid)
  640. {
  641. FindClientResourcesByType(client, PointerBarrierType, remove_master_func, &deviceid);
  642. }
  643. int
  644. XICreatePointerBarrier(ClientPtr client,
  645. xXFixesCreatePointerBarrierReq * stuff)
  646. {
  647. int err;
  648. struct PointerBarrierClient *barrier;
  649. struct PointerBarrier b;
  650. b.x1 = stuff->x1;
  651. b.x2 = stuff->x2;
  652. b.y1 = stuff->y1;
  653. b.y2 = stuff->y2;
  654. if (!barrier_is_horizontal(&b) && !barrier_is_vertical(&b))
  655. return BadValue;
  656. /* no 0-sized barriers */
  657. if (barrier_is_horizontal(&b) && barrier_is_vertical(&b))
  658. return BadValue;
  659. /* no infinite barriers on the wrong axis */
  660. if (barrier_is_horizontal(&b) && (b.y1 < 0 || b.y2 < 0))
  661. return BadValue;
  662. if (barrier_is_vertical(&b) && (b.x1 < 0 || b.x2 < 0))
  663. return BadValue;
  664. if ((err = CreatePointerBarrierClient(client, stuff, &barrier)))
  665. return err;
  666. if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier))
  667. return BadAlloc;
  668. return Success;
  669. }
  670. int
  671. XIDestroyPointerBarrier(ClientPtr client,
  672. xXFixesDestroyPointerBarrierReq * stuff)
  673. {
  674. int err;
  675. void *barrier;
  676. err = dixLookupResourceByType((void **) &barrier, stuff->barrier,
  677. PointerBarrierType, client, DixDestroyAccess);
  678. if (err != Success) {
  679. client->errorValue = stuff->barrier;
  680. return err;
  681. }
  682. if (CLIENT_ID(stuff->barrier) != client->index)
  683. return BadAccess;
  684. FreeResource(stuff->barrier, RT_NONE);
  685. return Success;
  686. }
  687. int
  688. SProcXIBarrierReleasePointer(ClientPtr client)
  689. {
  690. xXIBarrierReleasePointerInfo *info;
  691. REQUEST(xXIBarrierReleasePointerReq);
  692. int i;
  693. info = (xXIBarrierReleasePointerInfo*) &stuff[1];
  694. swaps(&stuff->length);
  695. swapl(&stuff->num_barriers);
  696. for (i = 0; i < stuff->num_barriers; i++, info++) {
  697. swaps(&info->deviceid);
  698. swapl(&info->barrier);
  699. swapl(&info->eventid);
  700. }
  701. return (ProcXIBarrierReleasePointer(client));
  702. }
  703. int
  704. ProcXIBarrierReleasePointer(ClientPtr client)
  705. {
  706. int i;
  707. int err;
  708. struct PointerBarrierClient *barrier;
  709. struct PointerBarrier *b;
  710. xXIBarrierReleasePointerInfo *info;
  711. REQUEST(xXIBarrierReleasePointerReq);
  712. REQUEST_AT_LEAST_SIZE(xXIBarrierReleasePointerReq);
  713. info = (xXIBarrierReleasePointerInfo*) &stuff[1];
  714. for (i = 0; i < stuff->num_barriers; i++, info++) {
  715. struct PointerBarrierDevice *pbd;
  716. DeviceIntPtr dev;
  717. CARD32 barrier_id, event_id;
  718. _X_UNUSED CARD32 device_id;
  719. barrier_id = info->barrier;
  720. event_id = info->eventid;
  721. err = dixLookupDevice(&dev, info->deviceid, client, DixReadAccess);
  722. if (err != Success) {
  723. client->errorValue = BadDevice;
  724. return err;
  725. }
  726. err = dixLookupResourceByType((void **) &b, barrier_id,
  727. PointerBarrierType, client, DixReadAccess);
  728. if (err != Success) {
  729. client->errorValue = barrier_id;
  730. return err;
  731. }
  732. if (CLIENT_ID(barrier_id) != client->index)
  733. return BadAccess;
  734. barrier = container_of(b, struct PointerBarrierClient, barrier);
  735. pbd = GetBarrierDevice(barrier, dev->id);
  736. if (pbd->barrier_event_id == event_id)
  737. pbd->release_event_id = event_id;
  738. }
  739. return Success;
  740. }
  741. Bool
  742. XIBarrierInit(void)
  743. {
  744. int i;
  745. if (!dixRegisterPrivateKey(&BarrierScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
  746. return FALSE;
  747. for (i = 0; i < screenInfo.numScreens; i++) {
  748. ScreenPtr pScreen = screenInfo.screens[i];
  749. BarrierScreenPtr cs;
  750. cs = (BarrierScreenPtr) calloc(1, sizeof(BarrierScreenRec));
  751. if (!cs)
  752. return FALSE;
  753. xorg_list_init(&cs->barriers);
  754. SetBarrierScreen(pScreen, cs);
  755. }
  756. PointerBarrierType = CreateNewResourceType(BarrierFreeBarrier,
  757. "XIPointerBarrier");
  758. return PointerBarrierType;
  759. }
  760. void
  761. XIBarrierReset(void)
  762. {
  763. int i;
  764. for (i = 0; i < screenInfo.numScreens; i++) {
  765. ScreenPtr pScreen = screenInfo.screens[i];
  766. BarrierScreenPtr cs = GetBarrierScreen(pScreen);
  767. free(cs);
  768. SetBarrierScreen(pScreen, NULL);
  769. }
  770. }