grabs.c revision ed6184df
1/* 2 3Copyright 1987, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, 28 29 All Rights Reserved 30 31Permission to use, copy, modify, and distribute this software and its 32documentation for any purpose and without fee is hereby granted, 33provided that the above copyright notice appear in all copies and that 34both that copyright notice and this permission notice appear in 35supporting documentation, and that the name of Digital not be 36used in advertising or publicity pertaining to distribution of the 37software without specific, written prior permission. 38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42WHETHER IN AN action OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44SOFTWARE. 45 46*/ 47 48#ifdef HAVE_DIX_CONFIG_H 49#include <dix-config.h> 50#endif 51 52#include <X11/X.h> 53#include "misc.h" 54#include <X11/Xproto.h> 55#include <X11/extensions/XI2.h> 56#include "windowstr.h" 57#include "inputstr.h" 58#include "cursorstr.h" 59#include "dixgrabs.h" 60#include "xace.h" 61#include "exevents.h" 62#include "exglobals.h" 63#include "inpututils.h" 64#include "client.h" 65 66#define BITMASK(i) (((Mask)1) << ((i) & 31)) 67#define MASKIDX(i) ((i) >> 5) 68#define MASKWORD(buf, i) buf[MASKIDX(i)] 69#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i) 70#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i) 71#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i)) 72 73void 74PrintDeviceGrabInfo(DeviceIntPtr dev) 75{ 76 ClientPtr client; 77 LocalClientCredRec *lcc; 78 int i, j; 79 GrabInfoPtr devGrab = &dev->deviceGrab; 80 GrabPtr grab = devGrab->grab; 81 Bool clientIdPrinted = FALSE; 82 83 ErrorF("Active grab 0x%lx (%s) on device '%s' (%d):\n", 84 (unsigned long) grab->resource, 85 (grab->grabtype == XI2) ? "xi2" : 86 ((grab->grabtype == CORE) ? "core" : "xi1"), dev->name, dev->id); 87 88 client = clients[CLIENT_ID(grab->resource)]; 89 if (client) { 90 pid_t clientpid = GetClientPid(client); 91 const char *cmdname = GetClientCmdName(client); 92 const char *cmdargs = GetClientCmdArgs(client); 93 94 if ((clientpid > 0) && (cmdname != NULL)) { 95 ErrorF(" client pid %ld %s %s\n", 96 (long) clientpid, cmdname, cmdargs ? cmdargs : ""); 97 clientIdPrinted = TRUE; 98 } 99 else if (GetLocalClientCreds(client, &lcc) != -1) { 100 ErrorF(" client pid %ld uid %ld gid %ld\n", 101 (lcc->fieldsSet & LCC_PID_SET) ? (long) lcc->pid : 0, 102 (lcc->fieldsSet & LCC_UID_SET) ? (long) lcc->euid : 0, 103 (lcc->fieldsSet & LCC_GID_SET) ? (long) lcc->egid : 0); 104 FreeLocalClientCreds(lcc); 105 clientIdPrinted = TRUE; 106 } 107 } 108 if (!clientIdPrinted) { 109 ErrorF(" (no client information available for client %d)\n", 110 CLIENT_ID(grab->resource)); 111 } 112 113 /* XXX is this even correct? */ 114 if (devGrab->sync.other) 115 ErrorF(" grab ID 0x%lx from paired device\n", 116 (unsigned long) devGrab->sync.other->resource); 117 118 ErrorF(" at %ld (from %s grab)%s (device %s, state %d)\n", 119 (unsigned long) devGrab->grabTime.milliseconds, 120 devGrab->fromPassiveGrab ? "passive" : "active", 121 devGrab->implicitGrab ? " (implicit)" : "", 122 devGrab->sync.frozen ? "frozen" : "thawed", devGrab->sync.state); 123 124 if (grab->grabtype == CORE) { 125 ErrorF(" core event mask 0x%lx\n", 126 (unsigned long) grab->eventMask); 127 } 128 else if (grab->grabtype == XI) { 129 ErrorF(" xi1 event mask 0x%lx\n", 130 devGrab->implicitGrab ? (unsigned long) grab->deviceMask : 131 (unsigned long) grab->eventMask); 132 } 133 else if (grab->grabtype == XI2) { 134 for (i = 0; i < xi2mask_num_masks(grab->xi2mask); i++) { 135 const unsigned char *mask; 136 int print; 137 138 print = 0; 139 for (j = 0; j < XI2MASKSIZE; j++) { 140 mask = xi2mask_get_one_mask(grab->xi2mask, i); 141 if (mask[j]) { 142 print = 1; 143 break; 144 } 145 } 146 if (!print) 147 continue; 148 ErrorF(" xi2 event mask for device %d: 0x", dev->id); 149 for (j = 0; j < xi2mask_mask_size(grab->xi2mask); j++) 150 ErrorF("%x", mask[j]); 151 ErrorF("\n"); 152 } 153 } 154 155 if (devGrab->fromPassiveGrab) { 156 ErrorF(" passive grab type %d, detail 0x%x, " 157 "activating key %d\n", grab->type, grab->detail.exact, 158 devGrab->activatingKey); 159 } 160 161 ErrorF(" owner-events %s, kb %d ptr %d, confine %lx, cursor 0x%lx\n", 162 grab->ownerEvents ? "true" : "false", 163 grab->keyboardMode, grab->pointerMode, 164 grab->confineTo ? (unsigned long) grab->confineTo->drawable.id : 0, 165 grab->cursor ? (unsigned long) grab->cursor->id : 0); 166} 167 168void 169UngrabAllDevices(Bool kill_client) 170{ 171 DeviceIntPtr dev; 172 ClientPtr client; 173 174 ErrorF("Ungrabbing all devices%s; grabs listed below:\n", 175 kill_client ? " and killing their owners" : ""); 176 177 for (dev = inputInfo.devices; dev; dev = dev->next) { 178 if (!dev->deviceGrab.grab) 179 continue; 180 PrintDeviceGrabInfo(dev); 181 client = clients[CLIENT_ID(dev->deviceGrab.grab->resource)]; 182 if (!kill_client || !client || client->clientGone) 183 dev->deviceGrab.DeactivateGrab(dev); 184 if (kill_client) 185 CloseDownClient(client); 186 } 187 188 ErrorF("End list of ungrabbed devices\n"); 189} 190 191GrabPtr 192AllocGrab(const GrabPtr src) 193{ 194 GrabPtr grab = calloc(1, sizeof(GrabRec)); 195 196 if (grab) { 197 grab->xi2mask = xi2mask_new(); 198 if (!grab->xi2mask) { 199 free(grab); 200 grab = NULL; 201 } 202 else if (src && !CopyGrab(grab, src)) { 203 free(grab->xi2mask); 204 free(grab); 205 grab = NULL; 206 } 207 } 208 209 return grab; 210} 211 212GrabPtr 213CreateGrab(int client, DeviceIntPtr device, DeviceIntPtr modDevice, 214 WindowPtr window, enum InputLevel grabtype, GrabMask *mask, 215 GrabParameters *param, int type, 216 KeyCode keybut, /* key or button */ 217 WindowPtr confineTo, CursorPtr cursor) 218{ 219 GrabPtr grab; 220 221 grab = AllocGrab(NULL); 222 if (!grab) 223 return (GrabPtr) NULL; 224 grab->resource = FakeClientID(client); 225 grab->device = device; 226 grab->window = window; 227 if (grabtype == CORE || grabtype == XI) 228 grab->eventMask = mask->core; /* same for XI */ 229 else 230 grab->eventMask = 0; 231 grab->deviceMask = 0; 232 grab->ownerEvents = param->ownerEvents; 233 grab->keyboardMode = param->this_device_mode; 234 grab->pointerMode = param->other_devices_mode; 235 grab->modifiersDetail.exact = param->modifiers; 236 grab->modifiersDetail.pMask = NULL; 237 grab->modifierDevice = modDevice; 238 grab->type = type; 239 grab->grabtype = grabtype; 240 grab->detail.exact = keybut; 241 grab->detail.pMask = NULL; 242 grab->confineTo = confineTo; 243 grab->cursor = RefCursor(cursor); 244 grab->next = NULL; 245 246 if (grabtype == XI2) 247 xi2mask_merge(grab->xi2mask, mask->xi2mask); 248 return grab; 249 250} 251 252void 253FreeGrab(GrabPtr pGrab) 254{ 255 BUG_RETURN(!pGrab); 256 257 free(pGrab->modifiersDetail.pMask); 258 free(pGrab->detail.pMask); 259 260 if (pGrab->cursor) 261 FreeCursor(pGrab->cursor, (Cursor) 0); 262 263 xi2mask_free(&pGrab->xi2mask); 264 free(pGrab); 265} 266 267Bool 268CopyGrab(GrabPtr dst, const GrabPtr src) 269{ 270 Mask *mdetails_mask = NULL; 271 Mask *details_mask = NULL; 272 XI2Mask *xi2mask; 273 274 if (src->modifiersDetail.pMask) { 275 int len = MasksPerDetailMask * sizeof(Mask); 276 277 mdetails_mask = malloc(len); 278 if (!mdetails_mask) 279 return FALSE; 280 memcpy(mdetails_mask, src->modifiersDetail.pMask, len); 281 } 282 283 if (src->detail.pMask) { 284 int len = MasksPerDetailMask * sizeof(Mask); 285 286 details_mask = malloc(len); 287 if (!details_mask) { 288 free(mdetails_mask); 289 return FALSE; 290 } 291 memcpy(details_mask, src->detail.pMask, len); 292 } 293 294 if (!dst->xi2mask) { 295 xi2mask = xi2mask_new(); 296 if (!xi2mask) { 297 free(mdetails_mask); 298 free(details_mask); 299 return FALSE; 300 } 301 } 302 else { 303 xi2mask = dst->xi2mask; 304 xi2mask_zero(xi2mask, -1); 305 } 306 307 *dst = *src; 308 dst->modifiersDetail.pMask = mdetails_mask; 309 dst->detail.pMask = details_mask; 310 dst->xi2mask = xi2mask; 311 dst->cursor = RefCursor(src->cursor); 312 313 xi2mask_merge(dst->xi2mask, src->xi2mask); 314 315 return TRUE; 316} 317 318int 319DeletePassiveGrab(void *value, XID id) 320{ 321 GrabPtr g, prev; 322 GrabPtr pGrab = (GrabPtr) value; 323 324 /* it is OK if the grab isn't found */ 325 prev = 0; 326 for (g = (wPassiveGrabs(pGrab->window)); g; g = g->next) { 327 if (pGrab == g) { 328 if (prev) 329 prev->next = g->next; 330 else if (!(pGrab->window->optional->passiveGrabs = g->next)) 331 CheckWindowOptionalNeed(pGrab->window); 332 break; 333 } 334 prev = g; 335 } 336 FreeGrab(pGrab); 337 return Success; 338} 339 340static Mask * 341DeleteDetailFromMask(Mask *pDetailMask, unsigned int detail) 342{ 343 Mask *mask; 344 int i; 345 346 mask = malloc(sizeof(Mask) * MasksPerDetailMask); 347 if (mask) { 348 if (pDetailMask) 349 for (i = 0; i < MasksPerDetailMask; i++) 350 mask[i] = pDetailMask[i]; 351 else 352 for (i = 0; i < MasksPerDetailMask; i++) 353 mask[i] = ~0L; 354 BITCLEAR(mask, detail); 355 } 356 return mask; 357} 358 359static Bool 360IsInGrabMask(DetailRec firstDetail, 361 DetailRec secondDetail, unsigned int exception) 362{ 363 if (firstDetail.exact == exception) { 364 if (firstDetail.pMask == NULL) 365 return TRUE; 366 367 /* (at present) never called with two non-null pMasks */ 368 if (secondDetail.exact == exception) 369 return FALSE; 370 371 if (GETBIT(firstDetail.pMask, secondDetail.exact)) 372 return TRUE; 373 } 374 375 return FALSE; 376} 377 378static Bool 379IdenticalExactDetails(unsigned int firstExact, 380 unsigned int secondExact, unsigned int exception) 381{ 382 if ((firstExact == exception) || (secondExact == exception)) 383 return FALSE; 384 385 if (firstExact == secondExact) 386 return TRUE; 387 388 return FALSE; 389} 390 391static Bool 392DetailSupersedesSecond(DetailRec firstDetail, 393 DetailRec secondDetail, unsigned int exception) 394{ 395 if (IsInGrabMask(firstDetail, secondDetail, exception)) 396 return TRUE; 397 398 if (IdenticalExactDetails(firstDetail.exact, secondDetail.exact, exception)) 399 return TRUE; 400 401 return FALSE; 402} 403 404static Bool 405GrabSupersedesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab) 406{ 407 unsigned int any_modifier = (pFirstGrab->grabtype == XI2) ? 408 (unsigned int) XIAnyModifier : (unsigned int) AnyModifier; 409 if (!DetailSupersedesSecond(pFirstGrab->modifiersDetail, 410 pSecondGrab->modifiersDetail, any_modifier)) 411 return FALSE; 412 413 if (DetailSupersedesSecond(pFirstGrab->detail, 414 pSecondGrab->detail, (unsigned int) AnyKey)) 415 return TRUE; 416 417 return FALSE; 418} 419 420/** 421 * Compares two grabs and returns TRUE if the first grab matches the second 422 * grab. 423 * 424 * A match is when 425 * - the devices set for the grab are equal (this is optional). 426 * - the event types for both grabs are equal. 427 * - XXX 428 * 429 * @param ignoreDevice TRUE if the device settings on the grabs are to be 430 * ignored. 431 * @return TRUE if the grabs match or FALSE otherwise. 432 */ 433Bool 434GrabMatchesSecond(GrabPtr pFirstGrab, GrabPtr pSecondGrab, Bool ignoreDevice) 435{ 436 unsigned int any_modifier = (pFirstGrab->grabtype == XI2) ? 437 (unsigned int) XIAnyModifier : (unsigned int) AnyModifier; 438 439 if (pFirstGrab->grabtype != pSecondGrab->grabtype) 440 return FALSE; 441 442 if (pFirstGrab->grabtype == XI2) { 443 if (pFirstGrab->device == inputInfo.all_devices || 444 pSecondGrab->device == inputInfo.all_devices) { 445 /* do nothing */ 446 } 447 else if (pFirstGrab->device == inputInfo.all_master_devices) { 448 if (pSecondGrab->device != inputInfo.all_master_devices && 449 !IsMaster(pSecondGrab->device)) 450 return FALSE; 451 } 452 else if (pSecondGrab->device == inputInfo.all_master_devices) { 453 if (pFirstGrab->device != inputInfo.all_master_devices && 454 !IsMaster(pFirstGrab->device)) 455 return FALSE; 456 } 457 else if (pSecondGrab->device != pFirstGrab->device) 458 return FALSE; 459 } 460 else if (!ignoreDevice && 461 ((pFirstGrab->device != pSecondGrab->device) || 462 (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice))) 463 return FALSE; 464 465 if (pFirstGrab->type != pSecondGrab->type) 466 return FALSE; 467 468 if (GrabSupersedesSecond(pFirstGrab, pSecondGrab) || 469 GrabSupersedesSecond(pSecondGrab, pFirstGrab)) 470 return TRUE; 471 472 if (DetailSupersedesSecond(pSecondGrab->detail, pFirstGrab->detail, 473 (unsigned int) AnyKey) 474 && 475 DetailSupersedesSecond(pFirstGrab->modifiersDetail, 476 pSecondGrab->modifiersDetail, any_modifier)) 477 return TRUE; 478 479 if (DetailSupersedesSecond(pFirstGrab->detail, pSecondGrab->detail, 480 (unsigned int) AnyKey) 481 && 482 DetailSupersedesSecond(pSecondGrab->modifiersDetail, 483 pFirstGrab->modifiersDetail, any_modifier)) 484 return TRUE; 485 486 return FALSE; 487} 488 489static Bool 490GrabsAreIdentical(GrabPtr pFirstGrab, GrabPtr pSecondGrab) 491{ 492 unsigned int any_modifier = (pFirstGrab->grabtype == XI2) ? 493 (unsigned int) XIAnyModifier : (unsigned int) AnyModifier; 494 495 if (pFirstGrab->grabtype != pSecondGrab->grabtype) 496 return FALSE; 497 498 if (pFirstGrab->device != pSecondGrab->device || 499 (pFirstGrab->modifierDevice != pSecondGrab->modifierDevice) || 500 (pFirstGrab->type != pSecondGrab->type)) 501 return FALSE; 502 503 if (!(DetailSupersedesSecond(pFirstGrab->detail, 504 pSecondGrab->detail, 505 (unsigned int) AnyKey) && 506 DetailSupersedesSecond(pSecondGrab->detail, 507 pFirstGrab->detail, (unsigned int) AnyKey))) 508 return FALSE; 509 510 if (!(DetailSupersedesSecond(pFirstGrab->modifiersDetail, 511 pSecondGrab->modifiersDetail, 512 any_modifier) && 513 DetailSupersedesSecond(pSecondGrab->modifiersDetail, 514 pFirstGrab->modifiersDetail, any_modifier))) 515 return FALSE; 516 517 return TRUE; 518} 519 520/** 521 * Prepend the new grab to the list of passive grabs on the window. 522 * Any previously existing grab that matches the new grab will be removed. 523 * Adding a new grab that would override another client's grab will result in 524 * a BadAccess. 525 * 526 * @return Success or X error code on failure. 527 */ 528int 529AddPassiveGrabToList(ClientPtr client, GrabPtr pGrab) 530{ 531 GrabPtr grab; 532 Mask access_mode = DixGrabAccess; 533 int rc; 534 535 for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) { 536 if (GrabMatchesSecond(pGrab, grab, (pGrab->grabtype == CORE))) { 537 if (CLIENT_BITS(pGrab->resource) != CLIENT_BITS(grab->resource)) { 538 FreeGrab(pGrab); 539 return BadAccess; 540 } 541 } 542 } 543 544 if (pGrab->keyboardMode == GrabModeSync || 545 pGrab->pointerMode == GrabModeSync) 546 access_mode |= DixFreezeAccess; 547 rc = XaceHook(XACE_DEVICE_ACCESS, client, pGrab->device, access_mode); 548 if (rc != Success) 549 return rc; 550 551 /* Remove all grabs that match the new one exactly */ 552 for (grab = wPassiveGrabs(pGrab->window); grab; grab = grab->next) { 553 if (GrabsAreIdentical(pGrab, grab)) { 554 DeletePassiveGrabFromList(grab); 555 break; 556 } 557 } 558 559 if (!pGrab->window->optional && !MakeWindowOptional(pGrab->window)) { 560 FreeGrab(pGrab); 561 return BadAlloc; 562 } 563 564 pGrab->next = pGrab->window->optional->passiveGrabs; 565 pGrab->window->optional->passiveGrabs = pGrab; 566 if (AddResource(pGrab->resource, RT_PASSIVEGRAB, (void *) pGrab)) 567 return Success; 568 return BadAlloc; 569} 570 571/* the following is kinda complicated, because we need to be able to back out 572 * if any allocation fails 573 */ 574 575Bool 576DeletePassiveGrabFromList(GrabPtr pMinuendGrab) 577{ 578 GrabPtr grab; 579 GrabPtr *deletes, *adds; 580 Mask ***updates, **details; 581 int i, ndels, nadds, nups; 582 Bool ok; 583 unsigned int any_modifier; 584 unsigned int any_key; 585 586#define UPDATE(mask,exact) \ 587 if (!(details[nups] = DeleteDetailFromMask(mask, exact))) \ 588 ok = FALSE; \ 589 else \ 590 updates[nups++] = &(mask) 591 592 i = 0; 593 for (grab = wPassiveGrabs(pMinuendGrab->window); grab; grab = grab->next) 594 i++; 595 if (!i) 596 return TRUE; 597 deletes = xallocarray(i, sizeof(GrabPtr)); 598 adds = xallocarray(i, sizeof(GrabPtr)); 599 updates = xallocarray(i, sizeof(Mask **)); 600 details = xallocarray(i, sizeof(Mask *)); 601 if (!deletes || !adds || !updates || !details) { 602 free(details); 603 free(updates); 604 free(adds); 605 free(deletes); 606 return FALSE; 607 } 608 609 any_modifier = (pMinuendGrab->grabtype == XI2) ? 610 (unsigned int) XIAnyModifier : (unsigned int) AnyModifier; 611 any_key = (pMinuendGrab->grabtype == XI2) ? 612 (unsigned int) XIAnyKeycode : (unsigned int) AnyKey; 613 ndels = nadds = nups = 0; 614 ok = TRUE; 615 for (grab = wPassiveGrabs(pMinuendGrab->window); 616 grab && ok; grab = grab->next) { 617 if ((CLIENT_BITS(grab->resource) != CLIENT_BITS(pMinuendGrab->resource)) 618 || !GrabMatchesSecond(grab, pMinuendGrab, (grab->grabtype == CORE))) 619 continue; 620 if (GrabSupersedesSecond(pMinuendGrab, grab)) { 621 deletes[ndels++] = grab; 622 } 623 else if ((grab->detail.exact == any_key) 624 && (grab->modifiersDetail.exact != any_modifier)) { 625 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); 626 } 627 else if ((grab->modifiersDetail.exact == any_modifier) 628 && (grab->detail.exact != any_key)) { 629 UPDATE(grab->modifiersDetail.pMask, 630 pMinuendGrab->modifiersDetail.exact); 631 } 632 else if ((pMinuendGrab->detail.exact != any_key) 633 && (pMinuendGrab->modifiersDetail.exact != any_modifier)) { 634 GrabPtr pNewGrab; 635 GrabParameters param; 636 637 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); 638 639 memset(¶m, 0, sizeof(param)); 640 param.ownerEvents = grab->ownerEvents; 641 param.this_device_mode = grab->keyboardMode; 642 param.other_devices_mode = grab->pointerMode; 643 param.modifiers = any_modifier; 644 645 pNewGrab = CreateGrab(CLIENT_ID(grab->resource), grab->device, 646 grab->modifierDevice, grab->window, 647 grab->grabtype, 648 (GrabMask *) &grab->eventMask, 649 ¶m, (int) grab->type, 650 pMinuendGrab->detail.exact, 651 grab->confineTo, grab->cursor); 652 if (!pNewGrab) 653 ok = FALSE; 654 else if (!(pNewGrab->modifiersDetail.pMask = 655 DeleteDetailFromMask(grab->modifiersDetail.pMask, 656 pMinuendGrab->modifiersDetail. 657 exact)) 658 || (!pNewGrab->window->optional && 659 !MakeWindowOptional(pNewGrab->window))) { 660 FreeGrab(pNewGrab); 661 ok = FALSE; 662 } 663 else if (!AddResource(pNewGrab->resource, RT_PASSIVEGRAB, 664 (void *) pNewGrab)) 665 ok = FALSE; 666 else 667 adds[nadds++] = pNewGrab; 668 } 669 else if (pMinuendGrab->detail.exact == any_key) { 670 UPDATE(grab->modifiersDetail.pMask, 671 pMinuendGrab->modifiersDetail.exact); 672 } 673 else { 674 UPDATE(grab->detail.pMask, pMinuendGrab->detail.exact); 675 } 676 } 677 678 if (!ok) { 679 for (i = 0; i < nadds; i++) 680 FreeResource(adds[i]->resource, RT_NONE); 681 for (i = 0; i < nups; i++) 682 free(details[i]); 683 } 684 else { 685 for (i = 0; i < ndels; i++) 686 FreeResource(deletes[i]->resource, RT_NONE); 687 for (i = 0; i < nadds; i++) { 688 grab = adds[i]; 689 grab->next = grab->window->optional->passiveGrabs; 690 grab->window->optional->passiveGrabs = grab; 691 } 692 for (i = 0; i < nups; i++) { 693 free(*updates[i]); 694 *updates[i] = details[i]; 695 } 696 } 697 free(details); 698 free(updates); 699 free(adds); 700 free(deletes); 701 return ok; 702 703#undef UPDATE 704} 705 706Bool 707GrabIsPointerGrab(GrabPtr grab) 708{ 709 return (grab->type == ButtonPress || 710 grab->type == DeviceButtonPress || grab->type == XI_ButtonPress); 711} 712 713Bool 714GrabIsKeyboardGrab(GrabPtr grab) 715{ 716 return (grab->type == KeyPress || 717 grab->type == DeviceKeyPress || grab->type == XI_KeyPress); 718} 719 720Bool 721GrabIsGestureGrab(GrabPtr grab) 722{ 723 return (grab->type == XI_GesturePinchBegin || 724 grab->type == XI_GestureSwipeBegin); 725} 726