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