Home | History | Annotate | Line # | Download | only in src
      1 /*
      2 
      3 Copyright (c) 1993, Oracle and/or its affiliates.
      4 
      5 Permission is hereby granted, free of charge, to any person obtaining a
      6 copy of this software and associated documentation files (the "Software"),
      7 to deal in the Software without restriction, including without limitation
      8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9 and/or sell copies of the Software, and to permit persons to whom the
     10 Software is furnished to do so, subject to the following conditions:
     11 
     12 The above copyright notice and this permission notice (including the next
     13 paragraph) shall be included in all copies or substantial portions of the
     14 Software.
     15 
     16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     22 DEALINGS IN THE SOFTWARE.
     23 
     24 */
     25 /********************************************************
     26 
     27 Copyright 1988 by Hewlett-Packard Company
     28 Copyright 1987, 1988, 1989,1990 by Digital Equipment Corporation, Maynard, Massachusetts
     29 
     30 Permission to use, copy, modify, and distribute this software
     31 and its documentation for any purpose and without fee is hereby
     32 granted, provided that the above copyright notice appear in all
     33 copies and that both that copyright notice and this permission
     34 notice appear in supporting documentation, and that the names of
     35 Hewlett-Packard or Digital not be used in advertising or
     36 publicity pertaining to distribution of the software without specific,
     37 written prior permission.
     38 
     39 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     40 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     41 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     42 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     43 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     44 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     45 SOFTWARE.
     46 
     47 ********************************************************/
     48 
     49 /*
     50 
     51 Copyright 1987, 1988, 1989, 1990, 1994, 1998  The Open Group
     52 
     53 Permission to use, copy, modify, distribute, and sell this software and its
     54 documentation for any purpose is hereby granted without fee, provided that
     55 the above copyright notice appear in all copies and that both that
     56 copyright notice and this permission notice appear in supporting
     57 documentation.
     58 
     59 The above copyright notice and this permission notice shall be included in
     60 all copies or substantial portions of the Software.
     61 
     62 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     63 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     64 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     65 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     66 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     67 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     68 
     69 Except as contained in this notice, the name of The Open Group shall not be
     70 used in advertising or otherwise to promote the sale, use or other dealings
     71 in 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 
    103 static void
    104 DeleteDetailFromMask(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 
    123 static Mask *
    124 CopyDetailMask(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 
    145 static XtServerGrabPtr
    146 CreateGrab(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 
    189 static void
    190 FreeGrab(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 
    200 typedef 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 
    210 static Bool
    211 IsInGrabMask(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 
    235 static Bool
    236 IdenticalExactDetails(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 
    256 static Bool
    257 DetailSupersedesSecond(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 
    276 static Bool
    277 GrabSupersedesSecond(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 
    323 static Bool
    324 GrabMatchesSecond(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 
    376 static void
    377 DeleteServerGrabFromList(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 
    487 static void
    488 DestroyPassiveList(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  */
    507 void
    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 
    541 XtServerGrabPtr
    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 
    586 static void
    587 ActiveHandler(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  */
    598 static void
    599 MakeGrab(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 
    639 static void
    640 MakeGrabs(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 
    672 static void
    673 RealizeHandler(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 
    701 static void
    702 GrabKeyOrButton(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 
    751 static void
    752 UngrabKeyOrButton(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 
    799 void
    800 XtGrabKey(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 
    816 void
    817 XtGrabButton(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 
    841 void
    842 XtUngrabKey(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 
    851 void
    852 XtUngrabButton(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  */
    864 static int
    865 GrabDevice(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 
    914 static void
    915 UngrabDevice(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  */
    945 int
    946 XtGrabKeyboard(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 
    968 void
    969 XtUngrabKeyboard(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  */
    981 int
    982 XtGrabPointer(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 
   1007 void
   1008 XtUngrabPointer(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 
   1017 void
   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