xibarriers.c revision 6e78d31f
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_H 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 62RESTYPE PointerBarrierType; 63 64static DevPrivateKeyRec BarrierScreenPrivateKeyRec; 65 66#define BarrierScreenPrivateKey (&BarrierScreenPrivateKeyRec) 67 68typedef struct PointerBarrierClient *PointerBarrierClientPtr; 69 70struct 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 80struct 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 94typedef struct _BarrierScreen { 95 struct xorg_list barriers; 96} BarrierScreenRec, *BarrierScreenPtr; 97 98#define GetBarrierScreen(s) ((BarrierScreenPtr)dixLookupPrivate(&(s)->devPrivates, BarrierScreenPrivateKey)) 99#define GetBarrierScreenIfSet(s) GetBarrierScreen(s) 100#define SetBarrierScreen(s,p) dixSetPrivate(&(s)->devPrivates, BarrierScreenPrivateKey, p) 101 102static struct PointerBarrierDevice *AllocBarrierDevice(void) 103{ 104 struct PointerBarrierDevice *pbd = NULL; 105 106 pbd = malloc(sizeof(struct PointerBarrierDevice)); 107 if (!pbd) 108 return NULL; 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 = FALSE; 114 pbd->seen = FALSE; 115 xorg_list_init(&pbd->entry); 116 117 return pbd; 118} 119 120static void FreePointerBarrierClient(struct PointerBarrierClient *c) 121{ 122 struct PointerBarrierDevice *pbd = NULL, *tmp = NULL; 123 124 xorg_list_for_each_entry_safe(pbd, tmp, &c->per_device, entry) { 125 free(pbd); 126 } 127 free(c); 128} 129 130static struct PointerBarrierDevice *GetBarrierDevice(struct PointerBarrierClient *c, int deviceid) 131{ 132 struct PointerBarrierDevice *pbd = NULL; 133 134 xorg_list_for_each_entry(pbd, &c->per_device, entry) { 135 if (pbd->deviceid == deviceid) 136 break; 137 } 138 139 BUG_WARN(!pbd); 140 return pbd; 141} 142 143static BOOL 144barrier_is_horizontal(const struct PointerBarrier *barrier) 145{ 146 return barrier->y1 == barrier->y2; 147} 148 149static BOOL 150barrier_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 */ 159int 160barrier_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; 167 if (x2 < x1) 168 direction |= BarrierNegativeX; 169 if (y2 > y1) 170 direction |= BarrierPositiveY; 171 if (y2 < y1) 172 direction |= BarrierNegativeY; 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 */ 185BOOL 186barrier_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 193static BOOL 194inside_segment(int v, int v1, int v2) 195{ 196 if (v1 < 0 && v2 < 0) /* line */ 197 return TRUE; 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)) 207#define F(t, a, b) ((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 */ 222BOOL 223barrier_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); 229 if (t < 0 || t > 1) 230 return FALSE; 231 232 /* Edge case: moving away from barrier. */ 233 if (x2 > x1 && t == 0) 234 return FALSE; 235 236 y = F(t, y1, y2); 237 if (!inside_segment(y, barrier->y1, barrier->y2)) 238 return FALSE; 239 240 *distance = sqrt((pow(y - y1, 2) + pow(barrier->x1 - x1, 2))); 241 return TRUE; 242 } 243 else { 244 float t, x; 245 t = T(barrier->y1, y1, y2); 246 if (t < 0 || t > 1) 247 return FALSE; 248 249 /* Edge case: moving away from barrier. */ 250 if (y2 > y1 && t == 0) 251 return FALSE; 252 253 x = F(t, x1, x2); 254 if (!inside_segment(x, barrier->x1, barrier->x2)) 255 return FALSE; 256 257 *distance = sqrt((pow(x - x1, 2) + pow(barrier->y1 - y1, 2))); 258 return TRUE; 259 } 260} 261 262#define HIT_EDGE_EXTENTS 2 263static BOOL 264barrier_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) 277 x1 -= HIT_EDGE_EXTENTS; 278 if (dir & BarrierNegativeX) 279 x2 += HIT_EDGE_EXTENTS; 280 } 281 if (barrier_is_horizontal(barrier)) { 282 if (dir & BarrierPositiveY) 283 y1 -= HIT_EDGE_EXTENTS; 284 if (dir & BarrierNegativeY) 285 y2 += HIT_EDGE_EXTENTS; 286 } 287 288 return x >= x1 && x <= x2 && y >= y1 && y <= y2; 289} 290 291static BOOL 292barrier_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 TRUE; 302 303 master_id = GetMaster(dev, POINTER_OR_FLOAT)->id; 304 305 for (i = 0; i < client->num_devices; i++) { 306 int device_id = client->device_ids[i]; 307 if (device_id == XIAllDevices || 308 device_id == XIAllMasterDevices || 309 device_id == master_id) 310 return TRUE; 311 } 312 313 return FALSE; 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 */ 326static struct PointerBarrierClient * 327barrier_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; 332 double min_distance = INT_MAX; /* can't get higher than that in X anyway */ 333 334 xorg_list_for_each_entry(c, &cs->barriers, 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 */ 368void 369barrier_clamp_to_barrier(struct PointerBarrier *barrier, int dir, int *x, 370 int *y) 371{ 372 if (barrier_is_vertical(barrier)) { 373 if ((dir & BarrierNegativeX) & ~barrier->directions) 374 *x = barrier->x1; 375 if ((dir & BarrierPositiveX) & ~barrier->directions) 376 *x = barrier->x1 - 1; 377 } 378 if (barrier_is_horizontal(barrier)) { 379 if ((dir & BarrierNegativeY) & ~barrier->directions) 380 *y = barrier->y1; 381 if ((dir & BarrierPositiveY) & ~barrier->directions) 382 *y = barrier->y1 - 1; 383 } 384} 385 386void 387input_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); 395 int x = dest_x, 396 y = dest_y; 397 int dir; 398 struct PointerBarrier *nearest = NULL; 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_POINTER); 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 = TRUE; 451 pbd->hit = TRUE; 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 | BarrierPositiveX); 461 current_x = x; 462 } 463 else if (barrier_is_horizontal(nearest)) { 464 dir &= ~(BarrierNegativeY | BarrierPositiveY); 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) { 484 struct PointerBarrierDevice *pbd; 485 int flags = 0; 486 487 pbd = GetBarrierDevice(c, master->id); 488 pbd->seen = FALSE; 489 if (!pbd->hit) 490 continue; 491 492 if (barrier_inside_hit_box(&c->barrier, x, y)) 493 continue; 494 495 pbd->hit = FALSE; 496 497 ev.type = ET_BarrierLeave; 498 499 if (pbd->barrier_event_id == pbd->release_event_id) 500 flags |= XIBarrierPointerReleased; 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 526static void 527sort_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); 535 *b = max(A, B); 536} 537 538static int 539CreatePointerBarrierClient(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 BadAlloc; 558 } 559 560 xorg_list_init(&ret->per_device); 561 562 err = dixLookupWindow(&pWin, stuff->window, client, DixReadAccess); 563 if (err != Success) { 564 client->errorValue = stuff->window; 565 goto error; 566 } 567 568 screen = pWin->drawable.pScreen; 569 cs = GetBarrierScreen(screen); 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; 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))) { 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) { 602 struct PointerBarrierDevice *pbd; 603 604 if (dev->type != MASTER_POINTER) 605 continue; 606 607 pbd = AllocBarrierDevice(); 608 if (!pbd) { 609 err = BadAlloc; 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 | BarrierNegativeX); 627 if (barrier_is_vertical(&ret->barrier)) 628 ret->barrier.directions &= ~(BarrierPositiveY | BarrierNegativeY); 629 xorg_list_add(&ret->entry, &cs->barriers); 630 631 *client_out = ret; 632 return Success; 633 634 error: 635 *client_out = NULL; 636 FreePointerBarrierClient(ret); 637 return err; 638} 639 640static int 641BarrierFreeBarrier(void *data, XID id) 642{ 643 struct PointerBarrierClient *c; 644 Time ms = GetTimeInMillis(); 645 DeviceIntPtr dev = NULL; 646 ScreenPtr screen; 647 648 c = container_of(data, 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, 671 }; 672 673 674 if (dev->type != MASTER_POINTER) 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 Success; 696} 697 698static 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); 707 708 709 pbd = AllocBarrierDevice(); 710 pbd->deviceid = *deviceid; 711 712 xorg_list_add(&pbd->entry, &barrier->per_device); 713} 714 715static 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); 726 if (rc != Success) 727 return; 728 729 b = res; 730 barrier = container_of(b, 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, 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 759void XIBarrierNewMasterDevice(ClientPtr client, int deviceid) 760{ 761 FindClientResourcesByType(client, PointerBarrierType, add_master_func, &deviceid); 762} 763 764void XIBarrierRemoveMasterDevice(ClientPtr client, int deviceid) 765{ 766 FindClientResourcesByType(client, PointerBarrierType, remove_master_func, &deviceid); 767} 768 769int 770XICreatePointerBarrier(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 BadValue; 784 785 /* no 0-sized barriers */ 786 if (barrier_is_horizontal(&b) && barrier_is_vertical(&b)) 787 return BadValue; 788 789 /* no infinite barriers on the wrong axis */ 790 if (barrier_is_horizontal(&b) && (b.y1 < 0 || b.y2 < 0)) 791 return BadValue; 792 793 if (barrier_is_vertical(&b) && (b.x1 < 0 || b.x2 < 0)) 794 return BadValue; 795 796 if ((err = CreatePointerBarrierClient(client, stuff, &barrier))) 797 return err; 798 799 if (!AddResource(stuff->barrier, PointerBarrierType, &barrier->barrier)) 800 return BadAlloc; 801 802 return Success; 803} 804 805int 806XIDestroyPointerBarrier(ClientPtr client, 807 xXFixesDestroyPointerBarrierReq * stuff) 808{ 809 int err; 810 void *barrier; 811 812 err = dixLookupResourceByType((void **) &barrier, stuff->barrier, 813 PointerBarrierType, client, DixDestroyAccess); 814 if (err != Success) { 815 client->errorValue = stuff->barrier; 816 return err; 817 } 818 819 if (CLIENT_ID(stuff->barrier) != client->index) 820 return BadAccess; 821 822 FreeResource(stuff->barrier, RT_NONE); 823 return Success; 824} 825 826int 827SProcXIBarrierReleasePointer(ClientPtr client) 828{ 829 xXIBarrierReleasePointerInfo *info; 830 REQUEST(xXIBarrierReleasePointerReq); 831 int i; 832 833 swaps(&stuff->length); 834 REQUEST_AT_LEAST_SIZE(xXIBarrierReleasePointerReq); 835 836 swapl(&stuff->num_barriers); 837 if (stuff->num_barriers > UINT32_MAX / sizeof(xXIBarrierReleasePointerInfo)) 838 return BadLength; 839 REQUEST_FIXED_SIZE(xXIBarrierReleasePointerReq, stuff->num_barriers * sizeof(xXIBarrierReleasePointerInfo)); 840 841 info = (xXIBarrierReleasePointerInfo*) &stuff[1]; 842 for (i = 0; i < stuff->num_barriers; i++, info++) { 843 swaps(&info->deviceid); 844 swapl(&info->barrier); 845 swapl(&info->eventid); 846 } 847 848 return (ProcXIBarrierReleasePointer(client)); 849} 850 851int 852ProcXIBarrierReleasePointer(ClientPtr client) 853{ 854 int i; 855 int err; 856 struct PointerBarrierClient *barrier; 857 struct PointerBarrier *b; 858 xXIBarrierReleasePointerInfo *info; 859 860 REQUEST(xXIBarrierReleasePointerReq); 861 REQUEST_AT_LEAST_SIZE(xXIBarrierReleasePointerReq); 862 if (stuff->num_barriers > UINT32_MAX / sizeof(xXIBarrierReleasePointerInfo)) 863 return BadLength; 864 REQUEST_FIXED_SIZE(xXIBarrierReleasePointerReq, stuff->num_barriers * sizeof(xXIBarrierReleasePointerInfo)); 865 866 info = (xXIBarrierReleasePointerInfo*) &stuff[1]; 867 for (i = 0; i < stuff->num_barriers; i++, info++) { 868 struct PointerBarrierDevice *pbd; 869 DeviceIntPtr dev; 870 CARD32 barrier_id, event_id; 871 _X_UNUSED CARD32 device_id; 872 873 barrier_id = info->barrier; 874 event_id = info->eventid; 875 876 err = dixLookupDevice(&dev, info->deviceid, client, DixReadAccess); 877 if (err != Success) { 878 client->errorValue = BadDevice; 879 return err; 880 } 881 882 err = dixLookupResourceByType((void **) &b, barrier_id, 883 PointerBarrierType, client, DixReadAccess); 884 if (err != Success) { 885 client->errorValue = barrier_id; 886 return err; 887 } 888 889 if (CLIENT_ID(barrier_id) != client->index) 890 return BadAccess; 891 892 893 barrier = container_of(b, struct PointerBarrierClient, barrier); 894 895 pbd = GetBarrierDevice(barrier, dev->id); 896 897 if (pbd->barrier_event_id == event_id) 898 pbd->release_event_id = event_id; 899 } 900 901 return Success; 902} 903 904Bool 905XIBarrierInit(void) 906{ 907 int i; 908 909 if (!dixRegisterPrivateKey(&BarrierScreenPrivateKeyRec, PRIVATE_SCREEN, 0)) 910 return FALSE; 911 912 for (i = 0; i < screenInfo.numScreens; i++) { 913 ScreenPtr pScreen = screenInfo.screens[i]; 914 BarrierScreenPtr cs; 915 916 cs = (BarrierScreenPtr) calloc(1, sizeof(BarrierScreenRec)); 917 if (!cs) 918 return FALSE; 919 xorg_list_init(&cs->barriers); 920 SetBarrierScreen(pScreen, cs); 921 } 922 923 PointerBarrierType = CreateNewResourceType(BarrierFreeBarrier, 924 "XIPointerBarrier"); 925 926 return PointerBarrierType; 927} 928 929void 930XIBarrierReset(void) 931{ 932 int i; 933 for (i = 0; i < screenInfo.numScreens; i++) { 934 ScreenPtr pScreen = screenInfo.screens[i]; 935 BarrierScreenPtr cs = GetBarrierScreen(pScreen); 936 free(cs); 937 SetBarrierScreen(pScreen, NULL); 938 } 939} 940