1/* 2 3Copyright (c) 1993, Oracle and/or its affiliates. 4 5Permission is hereby granted, free of charge, to any person obtaining a 6copy of this software and associated documentation files (the "Software"), 7to deal in the Software without restriction, including without limitation 8the rights to use, copy, modify, merge, publish, distribute, sublicense, 9and/or sell copies of the Software, and to permit persons to whom the 10Software is furnished to do so, subject to the following conditions: 11 12The above copyright notice and this permission notice (including the next 13paragraph) shall be included in all copies or substantial portions of the 14Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22DEALINGS IN THE SOFTWARE. 23 24*/ 25/******************************************************** 26 27Copyright 1988 by Hewlett-Packard Company 28Copyright 1987, 1988, 1989,1990 by Digital Equipment Corporation, Maynard, Massachusetts 29 30Permission to use, copy, modify, and distribute this software 31and its documentation for any purpose and without fee is hereby 32granted, provided that the above copyright notice appear in all 33copies and that both that copyright notice and this permission 34notice appear in supporting documentation, and that the names of 35Hewlett-Packard or Digital not be used in advertising or 36publicity pertaining to distribution of the software without specific, 37written prior permission. 38 39DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 40ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 41DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 42ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 43WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 44ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 45SOFTWARE. 46 47********************************************************/ 48 49/* 50 51Copyright 1987, 1988, 1989, 1990, 1994, 1998 The Open Group 52 53Permission to use, copy, modify, distribute, and sell this software and its 54documentation for any purpose is hereby granted without fee, provided that 55the above copyright notice appear in all copies and that both that 56copyright notice and this permission notice appear in supporting 57documentation. 58 59The above copyright notice and this permission notice shall be included in 60all copies or substantial portions of the Software. 61 62THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 63IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 64FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 65OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 66AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 67CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 68 69Except as contained in this notice, the name of The Open Group shall not be 70used in advertising or otherwise to promote the sale, use or other dealings 71in this Software without prior written authorization from The Open Group. 72 73*/ 74 75#ifdef HAVE_CONFIG_H 76#include <config.h> 77#endif 78#include "IntrinsicI.h" 79#include "StringDefs.h" 80#include "PassivGraI.h" 81 82/* typedef unsigned long Mask; */ 83#define BITMASK(i) (((Mask)1) << ((i) & 31)) 84#define MASKIDX(i) ((i) >> 5) 85#define MASKWORD(buf, i) buf[MASKIDX(i)] 86#define BITSET(buf, i) MASKWORD(buf, i) |= BITMASK(i) 87#define BITCLEAR(buf, i) MASKWORD(buf, i) &= ~BITMASK(i) 88#define GETBIT(buf, i) (MASKWORD(buf, i) & BITMASK(i)) 89#define MasksPerDetailMask 8 90 91#define pDisplay(grabPtr) (((grabPtr)->widget)->core.screen->display) 92#define pWindow(grabPtr) (((grabPtr)->widget)->core.window) 93 94/***************************************************************************/ 95/*********************** Internal Support Routines *************************/ 96/***************************************************************************/ 97 98/* 99 * Turn off (clear) the bit in the specified detail mask which is associated 100 * with the detail. 101 */ 102 103static void 104DeleteDetailFromMask(Mask **ppDetailMask, unsigned short detail) 105{ 106 Mask *pDetailMask = *ppDetailMask; 107 108 if (!pDetailMask) { 109 int i; 110 111 pDetailMask = XtMallocArray(MasksPerDetailMask, (Cardinal) sizeof(Mask)); 112 for (i = MasksPerDetailMask; --i >= 0;) 113 pDetailMask[i] = (unsigned long) (~0); 114 *ppDetailMask = pDetailMask; 115 } 116 BITCLEAR((pDetailMask), detail); 117} 118 119/* 120 * Make an exact copy of the specified detail mask. 121 */ 122 123static Mask * 124CopyDetailMask(const Mask *pOriginalDetailMask) 125{ 126 Mask *pTempMask; 127 int i; 128 129 if (!pOriginalDetailMask) 130 return NULL; 131 132 pTempMask = XtMallocArray(MasksPerDetailMask, (Cardinal) sizeof(Mask)); 133 134 for (i = 0; i < MasksPerDetailMask; i++) 135 pTempMask[i] = pOriginalDetailMask[i]; 136 137 return pTempMask; 138} 139 140/* 141 * Allocate a new grab entry, and fill in all of the fields using the 142 * specified parameters. 143 */ 144 145static XtServerGrabPtr 146CreateGrab(Widget widget, 147 Boolean ownerEvents, 148 Modifiers modifiers, 149 KeyCode keybut, 150 int pointer_mode, 151 int keyboard_mode, 152 Mask event_mask, 153 Window confine_to, 154 Cursor cursor, 155 Boolean need_ext) 156{ 157 XtServerGrabPtr grab; 158 159 if (confine_to || cursor) 160 need_ext = True; 161 grab = (XtServerGrabPtr) __XtMalloc(sizeof(XtServerGrabRec) + 162 (need_ext ? sizeof(XtServerGrabExtRec) 163 : 0)); 164 grab->next = NULL; 165 grab->widget = widget; 166 XtSetBit(grab->ownerEvents, ownerEvents); 167 XtSetBit(grab->pointerMode, pointer_mode); 168 XtSetBit(grab->keyboardMode, keyboard_mode); 169 grab->eventMask = (unsigned short) event_mask; 170 XtSetBit(grab->hasExt, need_ext); 171 grab->confineToIsWidgetWin = (XtWindow(widget) == confine_to); 172 grab->modifiers = (unsigned short) modifiers; 173 grab->keybut = keybut; 174 if (need_ext) { 175 XtServerGrabExtPtr ext = GRABEXT(grab); 176 177 ext->pModifiersMask = NULL; 178 ext->pKeyButMask = NULL; 179 ext->confineTo = confine_to; 180 ext->cursor = cursor; 181 } 182 return grab; 183} 184 185/* 186 * Free up the space occupied by a grab entry. 187 */ 188 189static void 190FreeGrab(XtServerGrabPtr pGrab) 191{ 192 if (pGrab->hasExt) { 193 XtServerGrabExtPtr ext = GRABEXT(pGrab); 194 XtFree((char *)ext->pModifiersMask); 195 XtFree((char *)ext->pKeyButMask); 196 } 197 XtFree((char *) pGrab); 198} 199 200typedef struct _DetailRec { 201 unsigned short exact; 202 Mask *pMask; 203} DetailRec, *DetailPtr; 204 205/* 206 * If the first detail is set to 'exception' and the second detail 207 * is contained in the mask of the first, then TRUE is returned. 208 */ 209 210static Bool 211IsInGrabMask(register DetailPtr firstDetail, 212 register DetailPtr secondDetail, 213 unsigned short exception) 214{ 215 if (firstDetail->exact == exception) { 216 if (!firstDetail->pMask) 217 return TRUE; 218 219 /* (at present) never called with two non-null pMasks */ 220 if (secondDetail->exact == exception) 221 return FALSE; 222 223 if (GETBIT(firstDetail->pMask, secondDetail->exact)) 224 return TRUE; 225 } 226 227 return FALSE; 228} 229 230/* 231 * If neither of the details is set to 'exception', and they match 232 * exactly, then TRUE is returned. 233 */ 234 235static Bool 236IdenticalExactDetails(unsigned short firstExact, 237 unsigned short secondExact, 238 unsigned short exception) 239{ 240 if ((firstExact == exception) || (secondExact == exception)) 241 return FALSE; 242 243 if (firstExact == secondExact) 244 return TRUE; 245 246 return FALSE; 247} 248 249/* 250 * If the first detail is set to 'exception', and its mask has the bit 251 * enabled which corresponds to the second detail, OR if neither of the 252 * details is set to 'exception' and the details match exactly, then 253 * TRUE is returned. 254 */ 255 256static Bool 257DetailSupersedesSecond(register DetailPtr firstDetail, 258 register DetailPtr secondDetail, 259 unsigned short exception) 260{ 261 if (IsInGrabMask(firstDetail, secondDetail, exception)) 262 return TRUE; 263 264 if (IdenticalExactDetails(firstDetail->exact, secondDetail->exact, 265 exception)) 266 return TRUE; 267 268 return FALSE; 269} 270 271/* 272 * If the two grab events match exactly, or if the first grab entry 273 * 'encompasses' the second grab entry, then TRUE is returned. 274 */ 275 276static Bool 277GrabSupersedesSecond(register XtServerGrabPtr pFirstGrab, 278 register XtServerGrabPtr pSecondGrab) 279{ 280 DetailRec first, second; 281 282 first.exact = pFirstGrab->modifiers; 283 if (pFirstGrab->hasExt) 284 first.pMask = GRABEXT(pFirstGrab)->pModifiersMask; 285 else 286 first.pMask = NULL; 287 second.exact = pSecondGrab->modifiers; 288 if (pSecondGrab->hasExt) 289 second.pMask = GRABEXT(pSecondGrab)->pModifiersMask; 290 else 291 second.pMask = NULL; 292 if (!DetailSupersedesSecond(&first, &second, (unsigned short) AnyModifier)) 293 return FALSE; 294 295 first.exact = pFirstGrab->keybut; 296 if (pFirstGrab->hasExt) 297 first.pMask = GRABEXT(pFirstGrab)->pKeyButMask; 298 else 299 first.pMask = NULL; 300 second.exact = pSecondGrab->keybut; 301 if (pSecondGrab->hasExt) 302 second.pMask = GRABEXT(pSecondGrab)->pKeyButMask; 303 else 304 second.pMask = NULL; 305 if (DetailSupersedesSecond(&first, &second, (unsigned short) AnyKey)) 306 return TRUE; 307 308 return FALSE; 309} 310 311/* 312 * Two grabs are considered to be matching if either of the following are true: 313 * 314 * 1) The two grab entries match exactly, or the first grab entry 315 * encompasses the second grab entry. 316 * 2) The second grab entry encompasses the first grab entry. 317 * 3) The keycodes match exactly, and one entry's modifiers encompasses 318 * the others. 319 * 4) The keycode for one entry encompasses the other, and the detail 320 * for the other entry encompasses the first. 321 */ 322 323static Bool 324GrabMatchesSecond(register XtServerGrabPtr pFirstGrab, 325 register XtServerGrabPtr pSecondGrab) 326{ 327 DetailRec firstD, firstM, secondD, secondM; 328 329 if (pDisplay(pFirstGrab) != pDisplay(pSecondGrab)) 330 return FALSE; 331 332 if (GrabSupersedesSecond(pFirstGrab, pSecondGrab)) 333 return TRUE; 334 335 if (GrabSupersedesSecond(pSecondGrab, pFirstGrab)) 336 return TRUE; 337 338 firstD.exact = pFirstGrab->keybut; 339 firstM.exact = pFirstGrab->modifiers; 340 if (pFirstGrab->hasExt) { 341 firstD.pMask = GRABEXT(pFirstGrab)->pKeyButMask; 342 firstM.pMask = GRABEXT(pFirstGrab)->pModifiersMask; 343 } 344 else { 345 firstD.pMask = NULL; 346 firstM.pMask = NULL; 347 } 348 secondD.exact = pSecondGrab->keybut; 349 secondM.exact = pSecondGrab->modifiers; 350 if (pSecondGrab->hasExt) { 351 secondD.pMask = GRABEXT(pSecondGrab)->pKeyButMask; 352 secondM.pMask = GRABEXT(pSecondGrab)->pModifiersMask; 353 } 354 else { 355 secondD.pMask = NULL; 356 secondM.pMask = NULL; 357 } 358 359 if (DetailSupersedesSecond(&secondD, &firstD, (unsigned short) AnyKey) && 360 DetailSupersedesSecond(&firstM, &secondM, (unsigned short) AnyModifier)) 361 return TRUE; 362 363 if (DetailSupersedesSecond(&firstD, &secondD, (unsigned short) AnyKey) && 364 DetailSupersedesSecond(&secondM, &firstM, (unsigned short) AnyModifier)) 365 return TRUE; 366 367 return FALSE; 368} 369 370/* 371 * Delete a grab combination from the passive grab list. Each entry will 372 * be checked to see if it is affected by the grab being deleted. This 373 * may result in multiple entries being modified/deleted. 374 */ 375 376static void 377DeleteServerGrabFromList(XtServerGrabPtr *passiveListPtr, 378 XtServerGrabPtr pMinuendGrab) 379{ 380 register XtServerGrabPtr *next; 381 register XtServerGrabPtr grab; 382 register XtServerGrabExtPtr ext; 383 384 for (next = passiveListPtr; (grab = *next);) { 385 if (GrabMatchesSecond(grab, pMinuendGrab) && 386 (pDisplay(grab) == pDisplay(pMinuendGrab))) { 387 if (GrabSupersedesSecond(pMinuendGrab, grab)) { 388 /* 389 * The entry being deleted encompasses the list entry, 390 * so delete the list entry. 391 */ 392 *next = grab->next; 393 FreeGrab(grab); 394 continue; 395 } 396 397 if (!grab->hasExt) { 398 grab = (XtServerGrabPtr) 399 XtRealloc((char *) grab, (sizeof(XtServerGrabRec) + 400 sizeof(XtServerGrabExtRec))); 401 *next = grab; 402 grab->hasExt = True; 403 ext = GRABEXT(grab); 404 ext->pKeyButMask = NULL; 405 ext->pModifiersMask = NULL; 406 ext->confineTo = None; 407 ext->cursor = None; 408 } 409 else 410 ext = GRABEXT(grab); 411 if ((grab->keybut == AnyKey) && (grab->modifiers != AnyModifier)) { 412 /* 413 * If the list entry has the key detail of AnyKey, and 414 * a modifier detail not set to AnyModifier, then we 415 * simply need to turn off the key detail bit in the 416 * list entry's key detail mask. 417 */ 418 DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut); 419 } 420 else if ((grab->modifiers == AnyModifier) && 421 (grab->keybut != AnyKey)) { 422 /* 423 * The list entry has a specific key detail, but its 424 * modifier detail is set to AnyModifier; so, we only 425 * need to turn off the specified modifier combination 426 * in the list entry's modifier mask. 427 */ 428 DeleteDetailFromMask(&ext->pModifiersMask, 429 pMinuendGrab->modifiers); 430 } 431 else if ((pMinuendGrab->keybut != AnyKey) && 432 (pMinuendGrab->modifiers != AnyModifier)) { 433 /* 434 * The list entry has a key detail of AnyKey and a 435 * modifier detail of AnyModifier; the entry being 436 * deleted has a specific key and a specific modifier 437 * combination. Therefore, we need to mask off the 438 * keycode from the list entry, and also create a 439 * new entry for this keycode, which has a modifier 440 * mask set to AnyModifier & ~(deleted modifiers). 441 */ 442 XtServerGrabPtr pNewGrab; 443 444 DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut); 445 pNewGrab = CreateGrab(grab->widget, 446 (Boolean) grab->ownerEvents, 447 (Modifiers) AnyModifier, 448 pMinuendGrab->keybut, 449 (int) grab->pointerMode, 450 (int) grab->keyboardMode, 451 (Mask) 0, (Window) 0, (Cursor) 0, True); 452 GRABEXT(pNewGrab)->pModifiersMask = 453 CopyDetailMask(ext->pModifiersMask); 454 455 DeleteDetailFromMask(&GRABEXT(pNewGrab)->pModifiersMask, 456 pMinuendGrab->modifiers); 457 458 pNewGrab->next = *passiveListPtr; 459 *passiveListPtr = pNewGrab; 460 } 461 else if (pMinuendGrab->keybut == AnyKey) { 462 /* 463 * The list entry has keycode AnyKey and modifier 464 * AnyModifier; the entry being deleted has 465 * keycode AnyKey and specific modifiers. So we 466 * simply need to mask off the specified modifier 467 * combination. 468 */ 469 DeleteDetailFromMask(&ext->pModifiersMask, 470 pMinuendGrab->modifiers); 471 } 472 else { 473 /* 474 * The list entry has keycode AnyKey and modifier 475 * AnyModifier; the entry being deleted has a 476 * specific keycode and modifier AnyModifier. So 477 * we simply need to mask off the specified 478 * keycode. 479 */ 480 DeleteDetailFromMask(&ext->pKeyButMask, pMinuendGrab->keybut); 481 } 482 } 483 next = &(*next)->next; 484 } 485} 486 487static void 488DestroyPassiveList(XtServerGrabPtr *passiveListPtr) 489{ 490 XtServerGrabPtr next, grab; 491 492 for (next = *passiveListPtr; next;) { 493 grab = next; 494 next = grab->next; 495 496 /* not necessary to explicitly ungrab key or button; 497 * window is being destroyed so server will take care of it. 498 */ 499 500 FreeGrab(grab); 501 } 502} 503 504/* 505 * This function is called at widget destroy time to clean up 506 */ 507void 508_XtDestroyServerGrabs(Widget w, 509 XtPointer closure, 510 XtPointer call_data _X_UNUSED) 511{ 512 XtPerWidgetInput pwi = (XtPerWidgetInput) closure; 513 XtPerDisplayInput pdi; 514 515 LOCK_PROCESS; 516 pdi = _XtGetPerDisplayInput(XtDisplay(w)); 517 _XtClearAncestorCache(w); 518 UNLOCK_PROCESS; 519 520 /* Remove the active grab, if necessary */ 521 if ((pdi->keyboard.grabType != XtNoServerGrab) && 522 (pdi->keyboard.grab.widget == w)) { 523 pdi->keyboard.grabType = XtNoServerGrab; 524 pdi->activatingKey = (KeyCode) 0; 525 } 526 if ((pdi->pointer.grabType != XtNoServerGrab) && 527 (pdi->pointer.grab.widget == w)) 528 pdi->pointer.grabType = XtNoServerGrab; 529 530 DestroyPassiveList(&pwi->keyList); 531 DestroyPassiveList(&pwi->ptrList); 532 533 _XtFreePerWidgetInput(w, pwi); 534} 535 536/* 537 * If the incoming event is on the passive grab list, then activate 538 * the grab. The grab will remain in effect until the key is released. 539 */ 540 541XtServerGrabPtr 542_XtCheckServerGrabsOnWidget(XEvent *event, Widget widget, _XtBoolean isKeyboard) 543{ 544 register XtServerGrabPtr grab; 545 XtServerGrabRec tempGrab; 546 XtServerGrabPtr *passiveListPtr; 547 XtPerWidgetInput pwi; 548 549 LOCK_PROCESS; 550 pwi = _XtGetPerWidgetInput(widget, FALSE); 551 UNLOCK_PROCESS; 552 if (!pwi) 553 return (XtServerGrabPtr) NULL; 554 if (isKeyboard) 555 passiveListPtr = &pwi->keyList; 556 else 557 passiveListPtr = &pwi->ptrList; 558 559 /* 560 * if either there is no entry in the context manager or the entry 561 * is empty, or the keyboard is grabbed, then no work to be done 562 */ 563 if (!*passiveListPtr) 564 return (XtServerGrabPtr) NULL; 565 566 /* Take only the lower thirteen bits as modifier state. The X Keyboard 567 * Extension may be representing keyboard group state in two upper bits. 568 */ 569 tempGrab.widget = widget; 570 tempGrab.keybut = (KeyCode) event->xkey.keycode; /* also xbutton.button */ 571 tempGrab.modifiers = event->xkey.state & 0x1FFF; /*also xbutton.state */ 572 tempGrab.hasExt = False; 573 574 for (grab = *passiveListPtr; grab; grab = grab->next) { 575 if (GrabMatchesSecond(&tempGrab, grab)) 576 return (grab); 577 } 578 return (XtServerGrabPtr) NULL; 579} 580 581/* 582 * This handler is needed to guarantee that we see releases on passive 583 * button grabs for widgets that haven't selected for button release. 584 */ 585 586static void 587ActiveHandler(Widget widget _X_UNUSED, 588 XtPointer pdi _X_UNUSED, 589 XEvent *event _X_UNUSED, 590 Boolean *cont _X_UNUSED) 591{ 592 /* nothing */ 593} 594 595/* 596 * MakeGrab 597 */ 598static void 599MakeGrab(XtServerGrabPtr grab, 600 XtServerGrabPtr *passiveListPtr, 601 Boolean isKeyboard, 602 XtPerDisplayInput pdi, 603 XtPerWidgetInput pwi) 604{ 605 if (!isKeyboard && !pwi->active_handler_added) { 606 XtAddEventHandler(grab->widget, ButtonReleaseMask, FALSE, 607 ActiveHandler, (XtPointer) pdi); 608 pwi->active_handler_added = TRUE; 609 } 610 611 if (isKeyboard) { 612 XGrabKey(pDisplay(grab), 613 grab->keybut, grab->modifiers, 614 pWindow(grab), grab->ownerEvents, 615 grab->pointerMode, grab->keyboardMode); 616 } 617 else { 618 Window confineTo = None; 619 Cursor cursor = None; 620 621 if (grab->hasExt) { 622 if (grab->confineToIsWidgetWin) 623 confineTo = XtWindow(grab->widget); 624 else 625 confineTo = GRABEXT(grab)->confineTo; 626 cursor = GRABEXT(grab)->cursor; 627 } 628 XGrabButton(pDisplay(grab), 629 grab->keybut, grab->modifiers, 630 pWindow(grab), grab->ownerEvents, grab->eventMask, 631 grab->pointerMode, grab->keyboardMode, confineTo, cursor); 632 } 633 634 /* Add the new grab entry to the passive key grab list */ 635 grab->next = *passiveListPtr; 636 *passiveListPtr = grab; 637} 638 639static void 640MakeGrabs(XtServerGrabPtr *passiveListPtr, 641 Boolean isKeyboard, 642 XtPerDisplayInput pdi) 643{ 644 XtServerGrabPtr next = *passiveListPtr; 645 646 /* 647 * make MakeGrab build a new list that has had the merge 648 * processing done on it. Start with an empty list 649 * (passiveListPtr). 650 */ 651 LOCK_PROCESS; 652 *passiveListPtr = NULL; 653 while (next) { 654 XtServerGrabPtr grab; 655 XtPerWidgetInput pwi; 656 657 grab = next; 658 next = grab->next; 659 pwi = _XtGetPerWidgetInput(grab->widget, FALSE); 660 MakeGrab(grab, passiveListPtr, isKeyboard, pdi, pwi); 661 } 662 UNLOCK_PROCESS; 663} 664 665/* 666 * This function is the event handler attached to the associated widget 667 * when grabs need to be added, but the widget is not yet realized. When 668 * it is first mapped, this handler will be invoked, and it will add all 669 * needed grabs. 670 */ 671 672static void 673RealizeHandler(Widget widget, 674 XtPointer closure, 675 XEvent *event _X_UNUSED, 676 Boolean *cont _X_UNUSED) 677{ 678 XtPerWidgetInput pwi = (XtPerWidgetInput) closure; 679 XtPerDisplayInput pdi; 680 681 LOCK_PROCESS; 682 pdi = _XtGetPerDisplayInput(XtDisplay(widget)); 683 UNLOCK_PROCESS; 684 MakeGrabs(&pwi->keyList, KEYBOARD, pdi); 685 MakeGrabs(&pwi->ptrList, POINTER, pdi); 686 687 XtRemoveEventHandler(widget, XtAllEvents, True, 688 RealizeHandler, (XtPointer) pwi); 689 pwi->realize_handler_added = FALSE; 690} 691 692/***************************************************************************/ 693/**************************** Global Routines ******************************/ 694/***************************************************************************/ 695 696/* 697 * Routine used by an application to set up a passive grab for a key/modifier 698 * combination. 699 */ 700 701static void 702GrabKeyOrButton(Widget widget, 703 KeyCode keyOrButton, 704 Modifiers modifiers, 705 Boolean owner_events, 706 int pointer_mode, 707 int keyboard_mode, 708 Mask event_mask, 709 Window confine_to, 710 Cursor cursor, 711 Boolean isKeyboard) 712{ 713 XtServerGrabPtr *passiveListPtr; 714 XtServerGrabPtr newGrab; 715 XtPerWidgetInput pwi; 716 XtPerDisplayInput pdi; 717 718 XtCheckSubclass(widget, coreWidgetClass, "in XtGrabKey or XtGrabButton"); 719 LOCK_PROCESS; 720 pwi = _XtGetPerWidgetInput(widget, TRUE); 721 if (isKeyboard) 722 passiveListPtr = &pwi->keyList; 723 else 724 passiveListPtr = &pwi->ptrList; 725 pdi = _XtGetPerDisplayInput(XtDisplay(widget)); 726 UNLOCK_PROCESS; 727 newGrab = CreateGrab(widget, owner_events, modifiers, 728 keyOrButton, pointer_mode, keyboard_mode, 729 event_mask, confine_to, cursor, False); 730 /* 731 * if the widget is realized then process the entry into the grab 732 * list. else if the list is empty (i.e. first time) then add the 733 * event handler. then add the raw entry to the list for processing 734 * in the handler at realize time. 735 */ 736 if (XtIsRealized(widget)) 737 MakeGrab(newGrab, passiveListPtr, isKeyboard, pdi, pwi); 738 else { 739 if (!pwi->realize_handler_added) { 740 XtAddEventHandler(widget, StructureNotifyMask, FALSE, 741 RealizeHandler, (XtPointer) pwi); 742 pwi->realize_handler_added = TRUE; 743 } 744 745 while (*passiveListPtr) 746 passiveListPtr = &(*passiveListPtr)->next; 747 *passiveListPtr = newGrab; 748 } 749} 750 751static void 752UngrabKeyOrButton(Widget widget, 753 int keyOrButton, 754 Modifiers modifiers, 755 Boolean isKeyboard) 756{ 757 XtServerGrabRec tempGrab; 758 XtPerWidgetInput pwi; 759 760 XtCheckSubclass(widget, coreWidgetClass, 761 "in XtUngrabKey or XtUngrabButton"); 762 763 /* Build a temporary grab list entry */ 764 tempGrab.widget = widget; 765 tempGrab.modifiers = (unsigned short) modifiers; 766 tempGrab.keybut = (KeyCode) keyOrButton; 767 tempGrab.hasExt = False; 768 769 LOCK_PROCESS; 770 pwi = _XtGetPerWidgetInput(widget, FALSE); 771 UNLOCK_PROCESS; 772 /* 773 * if there is no entry in the context manager then somethings wrong 774 */ 775 if (!pwi) { 776 XtAppWarningMsg(XtWidgetToApplicationContext(widget), 777 "invalidGrab", "ungrabKeyOrButton", XtCXtToolkitError, 778 "Attempt to remove nonexistent passive grab", 779 NULL, NULL); 780 return; 781 } 782 783 if (XtIsRealized(widget)) { 784 if (isKeyboard) 785 XUngrabKey(widget->core.screen->display, 786 keyOrButton, (unsigned int) modifiers, 787 widget->core.window); 788 else 789 XUngrabButton(widget->core.screen->display, 790 (unsigned) keyOrButton, (unsigned int) modifiers, 791 widget->core.window); 792 } 793 794 /* Delete all entries which are encompassed by the specified grab. */ 795 DeleteServerGrabFromList(isKeyboard ? &pwi->keyList : &pwi->ptrList, 796 &tempGrab); 797} 798 799void 800XtGrabKey(Widget widget, 801 _XtKeyCode keycode, 802 Modifiers modifiers, 803 _XtBoolean owner_events, 804 int pointer_mode, 805 int keyboard_mode) 806{ 807 WIDGET_TO_APPCON(widget); 808 809 LOCK_APP(app); 810 GrabKeyOrButton(widget, (KeyCode) keycode, modifiers, 811 (Boolean) owner_events, pointer_mode, keyboard_mode, 812 (Mask) 0, (Window) None, (Cursor) None, KEYBOARD); 813 UNLOCK_APP(app); 814} 815 816void 817XtGrabButton(Widget widget, 818 int button, 819 Modifiers modifiers, 820 _XtBoolean owner_events, 821 unsigned int event_mask, 822 int pointer_mode, 823 int keyboard_mode, 824 Window confine_to, 825 Cursor cursor) 826{ 827 WIDGET_TO_APPCON(widget); 828 829 LOCK_APP(app); 830 GrabKeyOrButton(widget, (KeyCode) button, modifiers, (Boolean) owner_events, 831 pointer_mode, keyboard_mode, 832 (Mask) event_mask, confine_to, cursor, POINTER); 833 UNLOCK_APP(app); 834} 835 836/* 837 * Routine used by an application to clear a passive grab for a key/modifier 838 * combination. 839 */ 840 841void 842XtUngrabKey(Widget widget, _XtKeyCode keycode, Modifiers modifiers) 843{ 844 WIDGET_TO_APPCON(widget); 845 846 LOCK_APP(app); 847 UngrabKeyOrButton(widget, (int) keycode, modifiers, KEYBOARD); 848 UNLOCK_APP(app); 849} 850 851void 852XtUngrabButton(Widget widget, unsigned int button, Modifiers modifiers) 853{ 854 WIDGET_TO_APPCON(widget); 855 856 LOCK_APP(app); 857 UngrabKeyOrButton(widget, (KeyCode) button, modifiers, POINTER); 858 UNLOCK_APP(app); 859} 860 861/* 862 * Active grab of Device. clear any client side grabs so we don't lock 863 */ 864static int 865GrabDevice(Widget widget, 866 Boolean owner_events, 867 int pointer_mode, 868 int keyboard_mode, 869 Mask event_mask, 870 Window confine_to, 871 Cursor cursor, 872 Time time, 873 Boolean isKeyboard) 874{ 875 XtPerDisplayInput pdi; 876 int returnVal; 877 878 XtCheckSubclass(widget, coreWidgetClass, 879 "in XtGrabKeyboard or XtGrabPointer"); 880 if (!XtIsRealized(widget)) 881 return GrabNotViewable; 882 LOCK_PROCESS; 883 pdi = _XtGetPerDisplayInput(XtDisplay(widget)); 884 UNLOCK_PROCESS; 885 if (!isKeyboard) 886 returnVal = XGrabPointer(XtDisplay(widget), XtWindow(widget), 887 owner_events, (unsigned) event_mask, 888 pointer_mode, keyboard_mode, 889 confine_to, cursor, time); 890 else 891 returnVal = XGrabKeyboard(XtDisplay(widget), XtWindow(widget), 892 owner_events, pointer_mode, 893 keyboard_mode, time); 894 895 if (returnVal == GrabSuccess) { 896 XtDevice device; 897 898 device = isKeyboard ? &pdi->keyboard : &pdi->pointer; 899 900 /* fill in the server grab rec */ 901 device->grab.widget = widget; 902 device->grab.modifiers = 0; 903 device->grab.keybut = 0; 904 XtSetBit(device->grab.ownerEvents, owner_events); 905 XtSetBit(device->grab.pointerMode, pointer_mode); 906 XtSetBit(device->grab.keyboardMode, keyboard_mode); 907 device->grab.hasExt = False; 908 device->grabType = XtActiveServerGrab; 909 pdi->activatingKey = (KeyCode) 0; 910 } 911 return returnVal; 912} 913 914static void 915UngrabDevice(Widget widget, Time time, Boolean isKeyboard) 916{ 917 XtPerDisplayInput pdi; 918 XtDevice device; 919 920 LOCK_PROCESS; 921 pdi = _XtGetPerDisplayInput(XtDisplay(widget)); 922 UNLOCK_PROCESS; 923 device = isKeyboard ? &pdi->keyboard : &pdi->pointer; 924 925 XtCheckSubclass(widget, coreWidgetClass, 926 "in XtUngrabKeyboard or XtUngrabPointer"); 927 928 if (device->grabType != XtNoServerGrab) { 929 930 if (device->grabType != XtPseudoPassiveServerGrab 931 && XtIsRealized(widget)) { 932 if (isKeyboard) 933 XUngrabKeyboard(XtDisplay(widget), time); 934 else 935 XUngrabPointer(XtDisplay(widget), time); 936 } 937 device->grabType = XtNoServerGrab; 938 pdi->activatingKey = (KeyCode) 0; 939 } 940} 941 942/* 943 * Active grab of keyboard. clear any client side grabs so we don't lock 944 */ 945int 946XtGrabKeyboard(Widget widget, 947 _XtBoolean owner_events, 948 int pointer_mode, 949 int keyboard_mode, 950 Time time) 951{ 952 int retval; 953 954 WIDGET_TO_APPCON(widget); 955 956 LOCK_APP(app); 957 retval = GrabDevice(widget, (Boolean) owner_events, 958 pointer_mode, keyboard_mode, 959 (Mask) 0, (Window) None, (Cursor) None, time, KEYBOARD); 960 UNLOCK_APP(app); 961 return retval; 962} 963 964/* 965 * Ungrab the keyboard 966 */ 967 968void 969XtUngrabKeyboard(Widget widget, Time time) 970{ 971 WIDGET_TO_APPCON(widget); 972 973 LOCK_APP(app); 974 UngrabDevice(widget, time, KEYBOARD); 975 UNLOCK_APP(app); 976} 977 978/* 979 * grab the pointer 980 */ 981int 982XtGrabPointer(Widget widget, 983 _XtBoolean owner_events, 984 unsigned int event_mask, 985 int pointer_mode, 986 int keyboard_mode, 987 Window confine_to, 988 Cursor cursor, 989 Time time) 990{ 991 int retval; 992 993 WIDGET_TO_APPCON(widget); 994 995 LOCK_APP(app); 996 retval = GrabDevice(widget, (Boolean) owner_events, 997 pointer_mode, keyboard_mode, 998 (Mask) event_mask, confine_to, cursor, time, POINTER); 999 UNLOCK_APP(app); 1000 return retval; 1001} 1002 1003/* 1004 * Ungrab the pointer 1005 */ 1006 1007void 1008XtUngrabPointer(Widget widget, Time time) 1009{ 1010 WIDGET_TO_APPCON(widget); 1011 1012 LOCK_APP(app); 1013 UngrabDevice(widget, time, POINTER); 1014 UNLOCK_APP(app); 1015} 1016 1017void 1018_XtRegisterPassiveGrabs(Widget widget) 1019{ 1020 XtPerWidgetInput pwi = _XtGetPerWidgetInput(widget, FALSE); 1021 1022 if (pwi != NULL && !pwi->realize_handler_added) { 1023 XtAddEventHandler(widget, StructureNotifyMask, FALSE, 1024 RealizeHandler, (XtPointer) pwi); 1025 pwi->realize_handler_added = TRUE; 1026 } 1027} 1028