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