Annotation of micropolis/src/tk/tkgrab.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * tkGrab.c --
        !             3:  *
        !             4:  *     This file provides procedures that implement grabs for Tk.
        !             5:  *
        !             6:  * Copyright 1992 Regents of the University of California.
        !             7:  * Permission to use, copy, modify, and distribute this
        !             8:  * software and its documentation for any purpose and without
        !             9:  * fee is hereby granted, provided that the above copyright
        !            10:  * notice appear in all copies.  The University of California
        !            11:  * makes no representations about the suitability of this
        !            12:  * software for any purpose.  It is provided "as is" without
        !            13:  * express or implied warranty.
        !            14:  */
        !            15: 
        !            16: #ifndef lint
        !            17: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkGrab.c,v 1.18 92/08/07 09:55:31 ouster Exp $ SPRITE (Berkeley)";
        !            18: #endif
        !            19: 
        !            20: #include "tkconfig.h"
        !            21: #include "tkint.h"
        !            22: 
        !            23: /*
        !            24:  *-------------------------------------------------------------------
        !            25:  * Problems with current grab implementation (8/7/92):
        !            26:  *
        !            27:  * 1. In a local grab the synthesized events are always placed at the
        !            28:  *    front of the event queue.  If there are several grabs and ungrabs
        !            29:  *    in a row, the groups of events for the different grabs/ungrabs
        !            30:  *    end up in backwards order.
        !            31:  * 2. The variables serverWinPtr and pointerWinPtr are hardly used at
        !            32:  *    all and should probably be eliminated.
        !            33:  * 3. The fact that grabWinPtr is set at the time a grab is set or
        !            34:  *    released, rather than when its events are processed, means that
        !            35:  *    it can get out of sync with the event queue if there's a rapid
        !            36:  *    sequence of grabs or ungrabs.  The only solution I can think of
        !            37:  *    is to keep a parallel queue to the event queue to update grabWinPtr
        !            38:  *    (or, synthesize an event to change the pointer?).
        !            39:  *-------------------------------------------------------------------
        !            40:  */
        !            41: 
        !            42: /*
        !            43:  * Bit definitions for grabFlags field of TkDisplay structures:
        !            44:  *
        !            45:  * GRAB_GLOBAL                 1 means this is a global grab (we grabbed via
        !            46:  *                             the server so all applications are locked out.
        !            47:  *                             0 means this is a local grab that affects
        !            48:  *                             only this application.
        !            49:  * GRAB_BUTTON_RELEASE         1 means that a button-release event just
        !            50:  *                             occurred and we're in the middle of a sequence
        !            51:  *                             of Enter and Leave events with NotifyUngrab
        !            52:  *                             mode.
        !            53:  */
        !            54: 
        !            55: #define GRAB_GLOBAL            1
        !            56: #define GRAB_BUTTON_RELEASE    2
        !            57: 
        !            58: /*
        !            59:  * Forward declarations for procedures declared later in this file:
        !            60:  */
        !            61: 
        !            62: static void            ChangeEventWindow _ANSI_ARGS_((XEvent *eventPtr,
        !            63:                            TkWindow *winPtr));
        !            64: static void            MovePointer _ANSI_ARGS_((XEvent *eventPtr,
        !            65:                            TkWindow *sourcePtr, TkWindow *destPtr));
        !            66: static void            MovePointer2 _ANSI_ARGS_((TkWindow *sourcePtr,
        !            67:                            TkWindow *destPtr, int mode));
        !            68: 
        !            69: /*
        !            70:  *----------------------------------------------------------------------
        !            71:  *
        !            72:  * Tk_GrabCmd --
        !            73:  *
        !            74:  *     This procedure is invoked to process the "grab" Tcl command.
        !            75:  *     See the user documentation for details on what it does.
        !            76:  *
        !            77:  * Results:
        !            78:  *     A standard Tcl result.
        !            79:  *
        !            80:  * Side effects:
        !            81:  *     See the user documentation.
        !            82:  *
        !            83:  *----------------------------------------------------------------------
        !            84:  */
        !            85: 
        !            86:        /* ARGSUSED */
        !            87: int
        !            88: Tk_GrabCmd(clientData, interp, argc, argv)
        !            89:     ClientData clientData;     /* Main window associated with
        !            90:                                 * interpreter. */
        !            91:     Tcl_Interp *interp;                /* Current interpreter. */
        !            92:     int argc;                  /* Number of arguments. */
        !            93:     char **argv;               /* Argument strings. */
        !            94: {
        !            95:     TkWindow *winPtr = (TkWindow *) clientData;
        !            96:     int length, lockScreen;
        !            97:     char *window;
        !            98: 
        !            99:     if (argc > 3) {
        !           100:        badArgs:
        !           101:        Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           102:                argv[0], " ?-global? ?window?\"", (char *) NULL);
        !           103:        return TCL_ERROR;
        !           104:     }
        !           105:     if (argc == 1) {
        !           106:        if ((winPtr->dispPtr->grabWinPtr != NULL)
        !           107:                && (winPtr->dispPtr->grabWinPtr->mainPtr
        !           108:                == winPtr->mainPtr)) {
        !           109:            interp->result = Tk_PathName(winPtr->dispPtr->grabWinPtr);
        !           110:        } else {
        !           111:            interp->result = "none";
        !           112:        }
        !           113:        return TCL_OK;
        !           114:     }
        !           115:     if (argc == 3) {
        !           116:        length = strlen(argv[1]);
        !           117:        if (strncmp(argv[1], "-off", length) == 0) {
        !           118:            lockScreen = -1;
        !           119:        } else {
        !           120:            if ((strncmp(argv[1], "-global", length) != 0) || (length < 2)) {
        !           121:                goto badArgs;
        !           122:            }
        !           123:            lockScreen = 1;
        !           124:        }
        !           125:        window = argv[2];
        !           126:     } else {
        !           127:        lockScreen = 0;
        !           128:        window = argv[1];
        !           129:     }
        !           130:     if ((window[0] == '\0')
        !           131:            || (strncmp(window, "none", strlen(window)) == 0)) {
        !           132:        Tk_Ungrab((Tk_Window) winPtr);  
        !           133:     } else {
        !           134:        Tk_Window tkwin;
        !           135: 
        !           136:        tkwin = Tk_NameToWindow(interp, window, (Tk_Window) winPtr);
        !           137:        if (tkwin == NULL) {
        !           138:            return TCL_ERROR;
        !           139:        }
        !           140:        if (lockScreen < 0) {
        !           141:            Tk_Ungrab(tkwin);
        !           142:        } else {
        !           143:            return Tk_Grab(interp, tkwin, lockScreen);
        !           144:        }
        !           145:     }
        !           146:     return TCL_OK;
        !           147: }
        !           148: 
        !           149: /*
        !           150:  *----------------------------------------------------------------------
        !           151:  *
        !           152:  * Tk_Grab --
        !           153:  *
        !           154:  *     Grabs the pointer and keyboard, so that mouse-related events are
        !           155:  *     only reported relative to a given window and its descendants.
        !           156:  *
        !           157:  * Results:
        !           158:  *     A standard Tcl result is returned.  TCL_OK is the normal return
        !           159:  *     value;  if the grab could not be set then TCL_ERROR is returned
        !           160:  *     and interp->result will hold an error message.
        !           161:  *
        !           162:  * Side effects:
        !           163:  *     Once this call completes successfully, no window outside the
        !           164:  *     tree rooted at tkwin will receive pointer- or keyboard-related
        !           165:  *     events until the next call to Tk_Ungrab.  If a previous grab was
        !           166:  *     in effect within this application, then it is replaced with a new
        !           167:  *     one.
        !           168:  *
        !           169:  *----------------------------------------------------------------------
        !           170:  */
        !           171: 
        !           172: int
        !           173: Tk_Grab(interp, tkwin, grabGlobal)
        !           174:     Tcl_Interp *interp;                        /* Used for error reporting. */
        !           175:     Tk_Window tkwin;                   /* Window on whose behalf the pointer
        !           176:                                         * is to be grabbed. */
        !           177:     int grabGlobal;                    /* Non-zero means issue a grab to the
        !           178:                                         * server so that no other application
        !           179:                                         * gets mouse or keyboard events.
        !           180:                                         * Zero means the grab only applies
        !           181:                                         * within this application. */
        !           182: {
        !           183:     int grabResult;
        !           184:     TkWindow *winPtr = (TkWindow *) tkwin;
        !           185:     TkDisplay *dispPtr = winPtr->dispPtr;
        !           186:     int grabRequest, inSequence, ignoring, numEvents, i, diff;
        !           187:     XEvent *events, *eventPtr;
        !           188:     TkWindow *winPtr2;
        !           189: 
        !           190:     if (dispPtr->grabWinPtr != NULL) {
        !           191:        if ((dispPtr->grabWinPtr == winPtr)
        !           192:                && (grabGlobal == ((dispPtr->grabFlags & GRAB_GLOBAL) != 0))) {
        !           193:            return TCL_OK;
        !           194:        }
        !           195:        if (dispPtr->grabWinPtr->mainPtr != winPtr->mainPtr) {
        !           196:            alreadyGrabbed:
        !           197:            interp->result = "grab failed: another application has grab";
        !           198:            return TCL_ERROR;
        !           199:        }
        !           200:        Tk_Ungrab(tkwin);
        !           201:     }
        !           202: 
        !           203:     if (grabGlobal) {
        !           204:        grabRequest = NextRequest(dispPtr->display);
        !           205:        grabResult = XGrabPointer(dispPtr->display, Tk_WindowId(tkwin),
        !           206:                True, ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|PointerMotionMask,
        !           207:                GrabModeAsync, GrabModeAsync, None, None,
        !           208:                TkCurrentTime(dispPtr));
        !           209:        if (grabResult != 0) {
        !           210:            grabError:
        !           211:            if (grabResult == GrabNotViewable) {
        !           212:                interp->result = "grab failed: window not viewable";
        !           213:            } else if (grabResult == AlreadyGrabbed) {
        !           214:                goto alreadyGrabbed;
        !           215:            } else if (grabResult == GrabFrozen) {
        !           216:                interp->result = "grab failed: keyboard or pointer frozen";
        !           217:            } else if (grabResult == GrabInvalidTime) {
        !           218:                interp->result = "grab failed: invalid time";
        !           219:            } else {
        !           220:                char msg[100];
        !           221:        
        !           222:                sprintf(msg, "grab failed for unknown reason (code %d)",
        !           223:                        grabResult);
        !           224:                Tcl_AppendResult(interp, msg, (char *) NULL);
        !           225:            }
        !           226:            return TCL_ERROR;
        !           227:        }
        !           228:        grabResult = XGrabKeyboard(dispPtr->display, Tk_WindowId(tkwin),
        !           229:                False, GrabModeAsync, GrabModeAsync, TkCurrentTime(dispPtr));
        !           230:        if (grabResult != 0) {
        !           231:            XUngrabPointer(dispPtr->display, TkCurrentTime(dispPtr));
        !           232:            goto grabError;
        !           233:        }
        !           234:        dispPtr->grabFlags |= GRAB_GLOBAL;
        !           235:     } else {
        !           236:        /*
        !           237:         * The call to XUngrabPointer below is needed to release any
        !           238:         * existing auto-grab due to a button press.  This is needed
        !           239:         * so that local grabs behave the same as global grabs (the
        !           240:         * button grab is released by the X server in a global grab).
        !           241:         */
        !           242: 
        !           243:        XUngrabPointer(dispPtr->display, TkCurrentTime(dispPtr));
        !           244:        grabRequest = LastKnownRequestProcessed(dispPtr->display);
        !           245:        dispPtr->grabFlags &= ~GRAB_GLOBAL;
        !           246: 
        !           247:        /*
        !           248:         * Since we're not telling the server about the grab, we have
        !           249:         * to generate Leave and Enter events to move the pointer from
        !           250:         * its current window to the grab window.
        !           251:         */
        !           252: 
        !           253:        MovePointer2(dispPtr->pointerWinPtr, winPtr, NotifyGrab);
        !           254:     }
        !           255:     dispPtr->grabWinPtr = winPtr;
        !           256: 
        !           257:     /*
        !           258:      * When a grab occurs, X generates Enter and Leave events to move
        !           259:      * the pointer from its current window to the grab window, even if
        !           260:      * the current window is in the grab tree.  We don't want these
        !           261:      * events getting through to the application if the current window
        !           262:      * is in the grab tree.  In order to eliminate the bogus events,
        !           263:      * process all pending events and filter out the bogus ones.
        !           264:      *
        !           265:      * Also, filter out the final enter event into the grab window in
        !           266:      * any case:  this event shouldn't be delivered until the mouse really
        !           267:      * moves into that window.
        !           268:      *
        !           269:      * The code below reads in all the pending events, filters out the bad
        !           270:      * ones, and then pushes back all the events that weren't filtered.
        !           271:      * Another alternative would be to simply process the events
        !           272:      * immediately rather than pushing them back again.  However, this
        !           273:      * tends to interfere with scripts since it causes pending events
        !           274:      * to be processed during the "grab" command.  The "grab" command
        !           275:      * might have been invoked in the middle of some computation where
        !           276:      * it's a bad idea to process new events.
        !           277:      */
        !           278: 
        !           279:     XSync(dispPtr->display, False);
        !           280:     numEvents = QLength(dispPtr->display);
        !           281:     if (numEvents == 0) {
        !           282:        return TCL_OK;
        !           283:     }
        !           284:     events = (XEvent *) ckalloc((unsigned) (numEvents * sizeof(XEvent)));
        !           285:     for (i = 0; i < numEvents; i++) {
        !           286:        XNextEvent(dispPtr->display, &events[i]);
        !           287:     }
        !           288:     inSequence = ignoring = 0;
        !           289:     for (i = numEvents-1, eventPtr = events; i >= 0; i--, eventPtr++) {
        !           290:        if (((eventPtr->type != EnterNotify)
        !           291:                && (eventPtr->type != LeaveNotify))
        !           292:                || (eventPtr->xcrossing.mode != NotifyGrab)) {
        !           293:            continue;
        !           294:        }
        !           295: 
        !           296:        /*
        !           297:         * The diff caculcation below is trickier than you might think,
        !           298:         * due to the fact that the event serial number is unsigned and
        !           299:         * serial numbers can wrap around.
        !           300:         */
        !           301: 
        !           302:        diff = eventPtr->xcrossing.serial;
        !           303:        diff -= grabRequest;
        !           304:        if (!inSequence && (diff >= 0)) {
        !           305:            /*
        !           306:             * This is the first event of the grab sequence.  See if its
        !           307:             * window is in the grab tree and ignore the sequence if it is.
        !           308:             */
        !           309: 
        !           310:            inSequence = 1;
        !           311:            if (XFindContext(dispPtr->display, eventPtr->xcrossing.window,
        !           312:                    tkWindowContext, (void *) &winPtr2) == 0) {
        !           313:                for ( ; winPtr2 != NULL; winPtr2 = winPtr2->parentPtr) {
        !           314:                    if (winPtr2 == dispPtr->grabWinPtr) {
        !           315:                        ignoring = 1;
        !           316:                        break;
        !           317:                    }
        !           318:                }
        !           319:            }
        !           320:        }
        !           321:        if (ignoring) {
        !           322:            eventPtr->type = 0;
        !           323:        }
        !           324:        if (inSequence && (eventPtr->type == EnterNotify)
        !           325:                && (dispPtr->grabWinPtr->window
        !           326:                == eventPtr->xcrossing.window)) {
        !           327:            eventPtr->type = 0;
        !           328:            break;
        !           329:        }
        !           330:     }
        !           331:     for (i = numEvents-1, eventPtr = &events[i]; i >= 0; i--, eventPtr--) {
        !           332:        if (eventPtr->type != 0) {
        !           333:            XPutBackEvent(dispPtr->display, eventPtr);
        !           334:        }
        !           335:     }
        !           336:     ckfree((char *) events);
        !           337:     return TCL_OK;
        !           338: }
        !           339: 
        !           340: /*
        !           341:  *----------------------------------------------------------------------
        !           342:  *
        !           343:  * Tk_Ungrab --
        !           344:  *
        !           345:  *     Releases a grab on the mouse pointer and keyboard.
        !           346:  *
        !           347:  * Results:
        !           348:  *     None.
        !           349:  *
        !           350:  * Side effects:
        !           351:  *     Pointer and keyboard events will start being delivered to other
        !           352:  *     windows again.
        !           353:  *
        !           354:  *----------------------------------------------------------------------
        !           355:  */
        !           356: 
        !           357: void
        !           358: Tk_Ungrab(tkwin)
        !           359:     Tk_Window tkwin;                   /* Window that identifies display
        !           360:                                         * for grab to be released. */
        !           361: {
        !           362:     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
        !           363:     int inSequence, ignoring, ungrabRequest, numEvents, i, j, diff;
        !           364:     TkWindow *grabWinPtr, *winPtr;
        !           365:     XEvent *events, *eventPtr, *eventPtr2;
        !           366: 
        !           367:     grabWinPtr = dispPtr->grabWinPtr;
        !           368:     if (grabWinPtr == NULL) {
        !           369:        return;
        !           370:     }
        !           371:     dispPtr->grabWinPtr = NULL;
        !           372:     dispPtr->buttonWinPtr = NULL;
        !           373:     if (dispPtr->grabFlags & GRAB_GLOBAL) {
        !           374:        ungrabRequest = NextRequest(dispPtr->display);
        !           375:        XUngrabPointer(dispPtr->display, TkCurrentTime(dispPtr));
        !           376:        XUngrabKeyboard(dispPtr->display, TkCurrentTime(dispPtr));
        !           377:        XSync(dispPtr->display, False);
        !           378:     } else {
        !           379:        ungrabRequest = LastKnownRequestProcessed(dispPtr->display);
        !           380:        if ((dispPtr->ungrabWinPtr != NULL)
        !           381:                && (dispPtr->ungrabWinPtr->mainPtr != grabWinPtr->mainPtr)) {
        !           382: 
        !           383:            /*
        !           384:             * Don't report entries down into a window of a different
        !           385:             * application, since it's already seen those entries earlier.
        !           386:             */
        !           387: 
        !           388:            dispPtr->ungrabWinPtr = NULL;
        !           389:        }
        !           390:        MovePointer2(grabWinPtr, dispPtr->ungrabWinPtr, NotifyUngrab);
        !           391:     }
        !           392: 
        !           393:     /*
        !           394:      * We have to filter all the pending events in a fashion similar to
        !           395:      * Tk_Grab. As with grabs, the X server generates an Enter-Leave event
        !           396:      * sequence to move the pointer from the grab window back to its
        !           397:      * current window.  We need to ignore this sequence if the pointer
        !           398:      * is being moved to a window that's already in the grab tree.
        !           399:      */
        !           400: 
        !           401:     numEvents = QLength(dispPtr->display);
        !           402:     if (numEvents == 0) {
        !           403:        return;
        !           404:     }
        !           405:     events = (XEvent *) ckalloc((unsigned) (numEvents * sizeof(XEvent)));
        !           406:     for (i = 0; i < numEvents; i++) {
        !           407:        XNextEvent(dispPtr->display, &events[i]);
        !           408:     }
        !           409:     inSequence = ignoring = 0;
        !           410:     for (i = numEvents-1, eventPtr = events; i >= 0; i--, eventPtr++) {
        !           411:        if (((eventPtr->type != EnterNotify)
        !           412:                && (eventPtr->type != LeaveNotify))
        !           413:                || (eventPtr->xcrossing.mode != NotifyUngrab)) {
        !           414:            continue;
        !           415:        }
        !           416:        diff = eventPtr->xcrossing.serial;
        !           417:        diff -= ungrabRequest;
        !           418:        if (!inSequence && (diff >= 0)) {
        !           419: 
        !           420:            /*
        !           421:             * This is the first event of the ungrab sequence.  Scan forward
        !           422:             * looking for the final Enter event in the sequence.  Then see
        !           423:             * if that event's window is in the grab tree.
        !           424:             */
        !           425: 
        !           426:            inSequence = 1;
        !           427:            for (j = i, eventPtr2 = eventPtr; j >= 0; j--, eventPtr2++) {
        !           428:                if (eventPtr2->type == EnterNotify) {
        !           429:                    if (eventPtr2->xcrossing.mode != NotifyUngrab) {
        !           430:                        break;
        !           431:                    }
        !           432:                    if ((eventPtr2->xcrossing.detail != NotifyAncestor)
        !           433:                            && (eventPtr2->xcrossing.detail != NotifyInferior)
        !           434:                            && (eventPtr2->xcrossing.detail
        !           435:                                    != NotifyNonlinear)) {
        !           436:                        continue;
        !           437:                    }
        !           438:                    if (XFindContext(dispPtr->display,
        !           439:                            eventPtr2->xcrossing.window,
        !           440:                            tkWindowContext, (void *) &winPtr) == 0) {
        !           441:                        for ( ; winPtr != NULL; winPtr = winPtr->parentPtr) {
        !           442:                            if (winPtr == grabWinPtr) {
        !           443:                                ignoring = 1;
        !           444:                                break;
        !           445:                            }
        !           446:                        }
        !           447:                    }
        !           448:                    break;
        !           449:                } else if ((eventPtr2->type != LeaveNotify)
        !           450:                        || (eventPtr2->xcrossing.mode != NotifyUngrab)) {
        !           451:                    break;
        !           452:                }
        !           453:            }
        !           454:        }
        !           455:        if (ignoring) {
        !           456:            eventPtr->type = 0;
        !           457:        }
        !           458:     }
        !           459:     for (i = numEvents-1, eventPtr = &events[i]; i >= 0; i--, eventPtr--) {
        !           460:        if (eventPtr->type != 0) {
        !           461:            XPutBackEvent(dispPtr->display, eventPtr);
        !           462:        }
        !           463:     }
        !           464:     ckfree((char *) events);
        !           465: }
        !           466: 
        !           467: /*
        !           468:  *----------------------------------------------------------------------
        !           469:  *
        !           470:  * TkPointerEvent --
        !           471:  *
        !           472:  *     This procedure is called for each pointer-related event, before
        !           473:  *     the event has been processed.  It does various things to make
        !           474:  *     grabs work correctly.
        !           475:  *
        !           476:  * Results:
        !           477:  *     If the return value is 1 it means the event should be processed
        !           478:  *     (event handlers should be invoked).  If the return value is 0
        !           479:  *     it means the event should be ignored in order to make grabs
        !           480:  *     work correctly.  Note:  the event may be modified by this procedure.
        !           481:  *
        !           482:  * Side effects:
        !           483:  *     Grab state information may be updated.
        !           484:  *
        !           485:  *----------------------------------------------------------------------
        !           486:  */
        !           487: 
        !           488: int
        !           489: TkPointerEvent(eventPtr, winPtr)
        !           490:     register XEvent *eventPtr;         /* Pointer to the event. */
        !           491:     TkWindow *winPtr;                  /* Tk's information for window
        !           492:                                         * where event was reported. */
        !           493: {
        !           494:     register TkWindow *winPtr2;
        !           495:     TkDisplay *dispPtr = winPtr->dispPtr;
        !           496:     int outsideGrabTree = 0;
        !           497:     int originalFlags;
        !           498:     int appGrabbed = 0;                        /* Non-zero means event is being
        !           499:                                         * reported to an application that is
        !           500:                                         * affected by the grab. */
        !           501: #define ALL_BUTTONS \
        !           502:        (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask)
        !           503:     static unsigned int state[] = {
        !           504:        Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask
        !           505:     };
        !           506: 
        !           507:     /*
        !           508:      * Don't do any filtering on events generated by the event-sharing code.
        !           509:      */
        !           510: 
        !           511:     if (eventPtr == tkShareEventPtr) {
        !           512:        return 1;
        !           513:     }
        !           514: 
        !           515:     /*
        !           516:      * If a grab is in effect, see if the event is being reported to
        !           517:      * a window in the grab tree.  Also see if the event is being reported
        !           518:      * to an application that is affected by the grab.
        !           519:      */
        !           520: 
        !           521:     if (dispPtr->grabWinPtr != NULL) {
        !           522:        if ((winPtr->mainPtr == dispPtr->grabWinPtr->mainPtr)
        !           523:                || (dispPtr->grabFlags & GRAB_GLOBAL)) {
        !           524:            appGrabbed = 1;
        !           525:        }
        !           526:        for (winPtr2 = winPtr; winPtr2 != dispPtr->grabWinPtr;
        !           527:                winPtr2 = winPtr2->parentPtr) {
        !           528:            if (winPtr2 == NULL) {
        !           529:                outsideGrabTree = 1;
        !           530:                break;
        !           531:            }
        !           532:        }
        !           533:     }
        !           534: 
        !           535:     originalFlags = dispPtr->grabFlags;
        !           536:     dispPtr->grabFlags &= ~GRAB_BUTTON_RELEASE;
        !           537:     if ((eventPtr->type == EnterNotify) || (eventPtr->type == LeaveNotify)) {
        !           538:        if ((eventPtr->type == EnterNotify)
        !           539:                && (eventPtr->xcrossing.detail != NotifyVirtual)
        !           540:                && (eventPtr->xcrossing.detail != NotifyNonlinearVirtual)) {
        !           541:            if ((dispPtr->grabWinPtr == NULL)
        !           542:                    || (dispPtr->grabWinPtr->mainPtr == winPtr->mainPtr)) {
        !           543:                dispPtr->ungrabWinPtr = winPtr;
        !           544:            }
        !           545:            dispPtr->serverWinPtr = winPtr;
        !           546:        } else {
        !           547:            dispPtr->serverWinPtr = NULL;
        !           548:        }
        !           549:        if (dispPtr->grabWinPtr != NULL) {
        !           550:            if (eventPtr->xcrossing.mode == NotifyNormal) {
        !           551:                /*
        !           552:                 * When a grab is active, X continues to report enter and
        !           553:                 * leave events for windows outside the tree of the grab
        !           554:                 * window.  Detect these events and ignore them.
        !           555:                 */
        !           556: 
        !           557:                if (outsideGrabTree && appGrabbed) {
        !           558:                    return 0;
        !           559:                }
        !           560:     
        !           561:                /*
        !           562:                 * Make buttons have the same grab-like behavior inside a grab
        !           563:                 * as they do outside a grab:  do this by ignoring enter and
        !           564:                 * leave events except for the window in which the button was
        !           565:                 * pressed.
        !           566:                 */
        !           567: 
        !           568:                if ((dispPtr->buttonWinPtr != NULL)
        !           569:                        && (winPtr != dispPtr->buttonWinPtr)) {
        !           570:                    return 0;
        !           571:                }
        !           572:            } else if (eventPtr->xcrossing.mode == NotifyUngrab) {
        !           573:                /*
        !           574:                 * Keep the GRAB_BUTTON_RELEASE flag on if it used to be on.
        !           575:                 */
        !           576: 
        !           577:                dispPtr->grabFlags = originalFlags;
        !           578:                if (outsideGrabTree && appGrabbed
        !           579:                        && (dispPtr->grabFlags & GRAB_BUTTON_RELEASE)) {
        !           580:                    /*
        !           581:                     * The only way we get here is if a button was pressed,
        !           582:                     * then moved to a different window and released.  Enter
        !           583:                     * and leave events were deferred while the button was
        !           584:                     * down, but now we're getting them to move the pointer
        !           585:                     * back to the right window, and this particular event
        !           586:                     * is for a window outside the grab tree.  Ignore it.
        !           587:                     */
        !           588:     
        !           589:                    return 0;
        !           590:                }
        !           591:            }
        !           592:        }
        !           593: 
        !           594:        /*
        !           595:         * Keep track of the window containing the mouse, in order to
        !           596:         * detect various bogus event sequences.
        !           597:         */
        !           598: 
        !           599:        dispPtr->pointerWinPtr = dispPtr->serverWinPtr;
        !           600:        return 1;
        !           601:     }
        !           602:     if ((dispPtr->grabWinPtr == NULL) || !appGrabbed) {
        !           603:        return 1;
        !           604:     }
        !           605: 
        !           606:     if (eventPtr->type == MotionNotify) {
        !           607:        /*
        !           608:         * When grabs are active, X reports motion events relative to the
        !           609:         * window under the pointer.  Instead, it should report the events
        !           610:         * relative to the window the button went down in, if there is a
        !           611:         * button down.  Otherwise, if the pointer window is outside the
        !           612:         * subtree of the grab window, the events should be reported
        !           613:         * relative to the grab window.  Otherwise, the event should be
        !           614:         * reported to the pointer window.
        !           615:         */
        !           616: 
        !           617:        winPtr2 = winPtr;
        !           618:        if (dispPtr->buttonWinPtr != NULL) {
        !           619:            winPtr2 = dispPtr->buttonWinPtr;
        !           620:        } else if (outsideGrabTree || (dispPtr->serverWinPtr == NULL)) {
        !           621:            winPtr2 = dispPtr->grabWinPtr;
        !           622:        }
        !           623:        if (winPtr2 != winPtr) {
        !           624:            XEvent newEvent;
        !           625: 
        !           626:            newEvent = *eventPtr;
        !           627:            ChangeEventWindow(&newEvent, winPtr2);
        !           628:            XPutBackEvent(winPtr2->display, &newEvent);
        !           629:            return 0;
        !           630:        }
        !           631:        return 1;
        !           632:     }
        !           633: 
        !           634:     /*
        !           635:      * Process ButtonPress and ButtonRelease events:
        !           636:      * 1. Keep track of whether a button is down and what window it
        !           637:      *    went down in.
        !           638:      * 2. If the first button goes down outside the grab tree, pretend
        !           639:      *    it went down in the grab window.  Note: it's important to
        !           640:      *    redirect events to the grab window like this in order to make
        !           641:      *    things like menus work, where button presses outside the
        !           642:      *    grabbed menu need to be seen.  An application can always
        !           643:      *    ignore the events if they occur outside its window.
        !           644:      * 3. If a button press or release occurs outside the window where
        !           645:      *    the first button was pressed, retarget the event so it's reported
        !           646:      *    to the window where the first button was pressed.
        !           647:      * 4. If the last button is released in a window different than where
        !           648:      *    the first button was pressed, generate Enter/Leave events to
        !           649:      *    move the mouse from the button window to its current window.
        !           650:      * 5. If the grab is set at a time when a button is already down, or
        !           651:      *    if the window where the button was pressed was deleted, then
        !           652:      *    dispPtr->buttonWinPtr will stay NULL.  Just forget about the
        !           653:      *    auto-grab for the button press;  events will go to whatever
        !           654:      *    window contains the pointer.  If this window isn't in the grab
        !           655:      *    tree then redirect events to the grab window.
        !           656:      */
        !           657: 
        !           658:     if ((eventPtr->type == ButtonPress) || (eventPtr->type == ButtonRelease)) {
        !           659:        winPtr2 = dispPtr->buttonWinPtr;
        !           660:        if (winPtr2 == NULL) {
        !           661:            if (outsideGrabTree) {
        !           662:                winPtr2 = dispPtr->grabWinPtr;                  /* Note 5. */
        !           663:            } else {
        !           664:                winPtr2 = winPtr;                               /* Note 5. */
        !           665:            }
        !           666:        }
        !           667:        if (eventPtr->type == ButtonPress) {
        !           668:            if ((eventPtr->xbutton.state & ALL_BUTTONS) == 0) {
        !           669:                if (outsideGrabTree) {
        !           670:                    XEvent newEvent;
        !           671: 
        !           672:                    newEvent = *eventPtr;
        !           673:                    ChangeEventWindow(&newEvent, dispPtr->grabWinPtr);
        !           674:                    XPutBackEvent(dispPtr->display, &newEvent);
        !           675:                    return 0;                                   /* Note 2. */
        !           676:                }
        !           677:                dispPtr->buttonWinPtr = winPtr;
        !           678:                return 1;
        !           679:            }
        !           680:        } else {
        !           681:            if ((eventPtr->xbutton.state & ALL_BUTTONS)
        !           682:                    == state[eventPtr->xbutton.button - Button1]) {
        !           683:                if ((dispPtr->buttonWinPtr != winPtr)
        !           684:                        && (dispPtr->buttonWinPtr != NULL)) {
        !           685:                    XEvent newEvent;                            /* Note 4. */
        !           686: 
        !           687:                    /*
        !           688:                     * If the button release is made with pointer outside
        !           689:                     * all applications, X reports it relative to the grab
        !           690:                     * window.   Change the current window to NULL to
        !           691:                     * reflect that the pointer's outside everything.  Do
        !           692:                     * the same if the pointer's in a window that's not
        !           693:                     * part of the grab tree.
        !           694:                     */
        !           695: 
        !           696:                    if (outsideGrabTree || (dispPtr->serverWinPtr == NULL)) {
        !           697:                        winPtr = NULL;
        !           698:                    }
        !           699:                    newEvent = *eventPtr;
        !           700:                    newEvent.xcrossing.mode = NotifyUngrab;
        !           701:                    newEvent.xcrossing.focus = False;
        !           702:                    newEvent.xcrossing.state =
        !           703:                            eventPtr->xbutton.state & ~ALL_BUTTONS;
        !           704:                    MovePointer(&newEvent, dispPtr->buttonWinPtr, winPtr);
        !           705:                }
        !           706:                dispPtr->buttonWinPtr = NULL;
        !           707:                dispPtr->grabFlags |= GRAB_BUTTON_RELEASE;
        !           708:            }
        !           709:        }
        !           710:        if (winPtr2 != winPtr) {
        !           711:            XEvent newEvent;
        !           712: 
        !           713:            newEvent = *eventPtr;
        !           714:            ChangeEventWindow(&newEvent, winPtr2);
        !           715:            XPutBackEvent(dispPtr->display, &newEvent);
        !           716:            return 0;                                           /* Note 3. */
        !           717:        }
        !           718:     }
        !           719: 
        !           720:     return 1;
        !           721: }
        !           722: 
        !           723: /*
        !           724:  *----------------------------------------------------------------------
        !           725:  *
        !           726:  * ChangeEventWindow --
        !           727:  *
        !           728:  *     Given an event and a new window to which the event should be
        !           729:  *     retargeted, modify fields of the event so that the event is
        !           730:  *     properly retargeted to the new window.
        !           731:  *
        !           732:  * Results:
        !           733:  *     The following fields of eventPtr are modified:  window,
        !           734:  *     subwindow, x, y, same_screen.
        !           735:  *
        !           736:  * Side effects:
        !           737:  *     None.
        !           738:  *
        !           739:  *----------------------------------------------------------------------
        !           740:  */
        !           741: 
        !           742: static void
        !           743: ChangeEventWindow(eventPtr, winPtr)
        !           744:     register XEvent *eventPtr; /* Event to retarget.  Must have
        !           745:                                 * type ButtonPress, ButtonRelease, KeyPress,
        !           746:                                 * KeyRelease, MotionNotify, EnterNotify,
        !           747:                                 * or LeaveNotify. */
        !           748:     TkWindow *winPtr;          /* New target window for event. */
        !           749: {
        !           750:     int x, y, sameScreen, bd;
        !           751:     register TkWindow *childPtr;
        !           752: 
        !           753:     eventPtr->xmotion.window = Tk_WindowId(winPtr);
        !           754:     if (eventPtr->xmotion.root ==
        !           755:            RootWindow(winPtr->display, winPtr->screenNum)) {
        !           756:        Tk_GetRootCoords((Tk_Window) winPtr, &x, &y);
        !           757:        eventPtr->xmotion.x = eventPtr->xmotion.x_root - x;
        !           758:        eventPtr->xmotion.y = eventPtr->xmotion.y_root - y;
        !           759:        eventPtr->xmotion.subwindow = None;
        !           760:        for (childPtr = winPtr->childList; childPtr != NULL;
        !           761:                childPtr = childPtr->nextPtr) {
        !           762:            if (childPtr->flags & TK_TOP_LEVEL) {
        !           763:                continue;
        !           764:            }
        !           765:            x = eventPtr->xmotion.x - childPtr->changes.x;
        !           766:            y = eventPtr->xmotion.y - childPtr->changes.y;
        !           767:            bd = childPtr->changes.border_width;
        !           768:            if ((x >= -bd) && (y >= -bd)
        !           769:                    && (x < (childPtr->changes.width + bd))
        !           770:                    && (y < (childPtr->changes.width + bd))) {
        !           771:                eventPtr->xmotion.subwindow = childPtr->window;
        !           772:            }
        !           773:        }
        !           774:        sameScreen = 1;
        !           775:     } else {
        !           776:        eventPtr->xmotion.x = 0;
        !           777:        eventPtr->xmotion.y = 0;
        !           778:        eventPtr->xmotion.subwindow = None;
        !           779:        sameScreen = 0;
        !           780:     }
        !           781:     if (eventPtr->type == MotionNotify) {
        !           782:        eventPtr->xmotion.same_screen = sameScreen;
        !           783:     } else {
        !           784:        eventPtr->xbutton.same_screen = sameScreen;
        !           785:     }
        !           786: }
        !           787: 
        !           788: /*
        !           789:  *----------------------------------------------------------------------
        !           790:  *
        !           791:  * MovePointer --
        !           792:  *
        !           793:  *     This procedure synthesizes EnterNotify and LeaveNotify events
        !           794:  *     to correctly transfer the pointer from one window to another.
        !           795:  *
        !           796:  * Results:
        !           797:  *     None.
        !           798:  *
        !           799:  * Side effects:
        !           800:  *     Synthesized events may be pushed back onto the event queue.
        !           801:  *     The event pointed to by eventPtr is modified.
        !           802:  *
        !           803:  *----------------------------------------------------------------------
        !           804:  */
        !           805: 
        !           806: static void
        !           807: MovePointer(eventPtr, sourcePtr, destPtr)
        !           808:     XEvent *eventPtr;          /* A template X event.  Must have all fields
        !           809:                                 * properly set for EnterNotify and LeaveNotify
        !           810:                                 * events except window, subwindow, x, y,
        !           811:                                 * detail, and same_screen.  (x_root and y_root
        !           812:                                 * must be valid, even though x and y needn't
        !           813:                                 * be valid). */
        !           814:     TkWindow *sourcePtr;       /* Window currently containing pointer (NULL
        !           815:                                 * means it's not one managed by this
        !           816:                                 * process). */
        !           817:     TkWindow *destPtr;         /* Window that is to end up containing the
        !           818:                                 * pointer (NULL means it's not one managed
        !           819:                                 * by this process). */
        !           820: {
        !           821:     TkDisplay *dispPtr;
        !           822:     register TkWindow *ancestorPtr;    /* Lowest ancestor shared between
        !           823:                                         * sourcePtr and destPtr, or
        !           824:                                         * sourcePtr's top-level window if no
        !           825:                                         * shared ancestor. */
        !           826:     register TkWindow *winPtr;
        !           827:     int upLevels, downLevels, i, j;
        !           828: 
        !           829:     /*
        !           830:      * There are four possible cases to deal with:
        !           831:      *
        !           832:      * 1. SourcePtr and destPtr are the same.  There's nothing to do in
        !           833:      *    this case.
        !           834:      * 2. SourcePtr is an ancestor of destPtr in the same top-level
        !           835:      *    window.  Must generate events down the window tree from source
        !           836:      *    to dest.
        !           837:      * 3. DestPtr is an ancestor of sourcePtr in the same top-level
        !           838:      *    window.  Must generate events up the window tree from sourcePtr
        !           839:      *    to destPtr.
        !           840:      * 4. All other cases.  Must first generate events up the window tree
        !           841:      *    from sourcePtr to its top-level, then down from destPtr's
        !           842:      *    top-level to destPtr. This form is called "non-linear."
        !           843:      *
        !           844:      * The code below separates these four cases and decides how many levels
        !           845:      * up and down events have to be generated for.
        !           846:      */
        !           847: 
        !           848:     if (sourcePtr == destPtr) {
        !           849:        return;
        !           850:     }
        !           851: 
        !           852:     /*
        !           853:      * Mark destPtr and all of its ancestors with a special flag bit.
        !           854:      */
        !           855: 
        !           856:     if (destPtr != NULL) {
        !           857:        dispPtr = destPtr->dispPtr;
        !           858:        for (winPtr = destPtr; ; winPtr = winPtr->parentPtr) {
        !           859:            winPtr->flags |= TK_GRAB_FLAG;
        !           860:            if (winPtr->flags & TK_TOP_LEVEL) {
        !           861:                break;
        !           862:            }
        !           863:        }
        !           864:     } else {
        !           865:        dispPtr = sourcePtr->dispPtr;
        !           866:     }
        !           867: 
        !           868:     /*
        !           869:      * Search upwards from sourcePtr until an ancestor of destPtr is
        !           870:      * found or a top-level window is reached.  Remember if we pass out
        !           871:      * of the grab tree along the way, since this means we'll have to
        !           872:      * skip some of the events that would otherwise be generated.
        !           873:      */
        !           874: 
        !           875:     ancestorPtr = sourcePtr;
        !           876:     upLevels = 0;
        !           877:     if (sourcePtr != NULL) {
        !           878:        for (; ; upLevels++, ancestorPtr = ancestorPtr->parentPtr) {
        !           879:            if (ancestorPtr->flags & TK_GRAB_FLAG) {
        !           880:                break;
        !           881:            }
        !           882:            if (ancestorPtr->flags & TK_TOP_LEVEL)  {
        !           883:                upLevels++;
        !           884:                break;
        !           885:            }
        !           886:        }
        !           887:     }
        !           888: 
        !           889:     /*
        !           890:      * Search upwards from destPtr again, clearing the flag bits and
        !           891:      * remembering how many levels up we had to go.
        !           892:      */
        !           893: 
        !           894:     if (destPtr == NULL) {
        !           895:        downLevels = 0;
        !           896:     } else {
        !           897:        downLevels = -1;
        !           898:        for (i = 0, winPtr = destPtr; ; i++, winPtr = winPtr->parentPtr) {
        !           899:            winPtr->flags &= ~TK_GRAB_FLAG;
        !           900:            if (winPtr == ancestorPtr) {
        !           901:                downLevels = i;
        !           902:            }
        !           903:            if (winPtr->flags & TK_TOP_LEVEL) {
        !           904:                if (downLevels == -1) {
        !           905:                    downLevels = i+1;
        !           906:                }
        !           907:                break;
        !           908:            }
        !           909:        }
        !           910:     }
        !           911: 
        !           912:     /*
        !           913:      * Generate enter/leave events and push them back onto the event
        !           914:      * queue.  This has to be done backwards, since the last event
        !           915:      * pushed will be the first one processed.
        !           916:      */
        !           917: 
        !           918: #define PUSH_EVENT(w, t, d)                    \
        !           919:     if (w->window != None) {                   \
        !           920:        eventPtr->type = t;                     \
        !           921:        eventPtr->xcrossing.detail = d;         \
        !           922:        ChangeEventWindow(eventPtr, w);         \
        !           923:        XPutBackEvent(w->display, eventPtr);    \
        !           924:     }
        !           925: 
        !           926:     if (downLevels == 0) {
        !           927:     
        !           928:        /*
        !           929:         * SourcePtr is an inferior of destPtr.
        !           930:         */
        !           931: 
        !           932:        if (destPtr != NULL) {
        !           933:            PUSH_EVENT(destPtr, EnterNotify, NotifyInferior);
        !           934:        }
        !           935:        for (i = upLevels-1; i > 0; i--) {
        !           936:            for (winPtr = sourcePtr, j = 0; j < i;
        !           937:                    winPtr = winPtr->parentPtr, j++) {
        !           938:                if (winPtr == dispPtr->grabWinPtr) {
        !           939:                    goto nextIteration;
        !           940:                }
        !           941:            }
        !           942:            PUSH_EVENT(winPtr, LeaveNotify, NotifyVirtual);
        !           943:            nextIteration: continue;
        !           944:        }
        !           945:        PUSH_EVENT(sourcePtr, LeaveNotify, NotifyAncestor);
        !           946:     } else if (upLevels == 0) {
        !           947: 
        !           948:        /*
        !           949:         * DestPtr is an inferior of sourcePtr.
        !           950:         */
        !           951: 
        !           952:        if (destPtr != NULL) {
        !           953:            PUSH_EVENT(destPtr, EnterNotify, NotifyAncestor);
        !           954:        }
        !           955:        for (winPtr = destPtr->parentPtr, i = downLevels-1; i > 0;
        !           956:                winPtr = winPtr->parentPtr, i--) {
        !           957:            PUSH_EVENT(winPtr, EnterNotify, NotifyVirtual);
        !           958:        }
        !           959:        if (sourcePtr != NULL) {
        !           960:            PUSH_EVENT(sourcePtr, LeaveNotify, NotifyInferior);
        !           961:        }
        !           962:     } else {
        !           963: 
        !           964:        /*
        !           965:         * Non-linear:  neither window is an inferior of the other.
        !           966:         */
        !           967: 
        !           968:        if (destPtr != NULL) {
        !           969:            PUSH_EVENT(destPtr, EnterNotify, NotifyNonlinear);
        !           970:        }
        !           971:        if (destPtr != dispPtr->grabWinPtr) {
        !           972:            for (winPtr = destPtr->parentPtr, i = downLevels-1; i > 0;
        !           973:                    winPtr = winPtr->parentPtr, i--) {
        !           974:                PUSH_EVENT(winPtr, EnterNotify, NotifyNonlinearVirtual);
        !           975:                if (winPtr == dispPtr->grabWinPtr) {
        !           976:                    break;
        !           977:                }
        !           978:            }
        !           979:        }
        !           980:        for (i = upLevels-1; i > 0; i--) {
        !           981:            for (winPtr = sourcePtr, j = 0; j < i;
        !           982:                    winPtr = winPtr->parentPtr, j++) {
        !           983:                if (winPtr == dispPtr->grabWinPtr) {
        !           984:                    goto nextWindow;
        !           985:                }
        !           986:            }
        !           987:            PUSH_EVENT(winPtr, LeaveNotify, NotifyNonlinearVirtual);
        !           988:            nextWindow: continue;
        !           989:        }
        !           990:        PUSH_EVENT(sourcePtr, LeaveNotify, NotifyNonlinear);
        !           991:     }
        !           992: }
        !           993: 
        !           994: /*
        !           995:  *----------------------------------------------------------------------
        !           996:  *
        !           997:  * MovePointer2 --
        !           998:  *
        !           999:  *     This procedure synthesizes  EnterNotify and LeaveNotify events
        !          1000:  *     to correctly transfer the pointer from one window to another.
        !          1001:  *     It is different from MovePointer in that no template X event
        !          1002:  *     needs to be supplied;  this procedure generates the template
        !          1003:  *     event and calls MovePointer.
        !          1004:  *
        !          1005:  * Results:
        !          1006:  *     None.
        !          1007:  *
        !          1008:  * Side effects:
        !          1009:  *     Synthesized events may be pushed back onto the event queue.
        !          1010:  *
        !          1011:  *----------------------------------------------------------------------
        !          1012:  */
        !          1013: 
        !          1014: static void
        !          1015: MovePointer2(sourcePtr, destPtr, mode)
        !          1016:     TkWindow *sourcePtr;       /* Window currently containing pointer (NULL
        !          1017:                                 * means it's not one managed by this
        !          1018:                                 * process). */
        !          1019:     TkWindow *destPtr;         /* Window that is to end up containing the
        !          1020:                                 * pointer (NULL means it's not one managed
        !          1021:                                 * by this process). */
        !          1022:     int mode;                  /* Mode for enter/leave events, such as
        !          1023:                                 * NotifyNormal or NotifyUngrab. */
        !          1024: {
        !          1025:     XEvent event;
        !          1026:     Window dummy1, dummy2;
        !          1027:     int dummy3, dummy4;
        !          1028:     TkWindow *winPtr;
        !          1029: 
        !          1030:     winPtr = sourcePtr;
        !          1031:     if ((winPtr == NULL) || (winPtr->window == None)) {
        !          1032:        winPtr = destPtr;
        !          1033:        if ((winPtr == NULL) || (winPtr->window == None)) {
        !          1034:            return;
        !          1035:        }
        !          1036:     }
        !          1037: 
        !          1038:     event.xcrossing.serial = LastKnownRequestProcessed(winPtr->display);
        !          1039:     event.xcrossing.send_event = False;
        !          1040:     event.xcrossing.display = winPtr->display;
        !          1041:     event.xcrossing.root = RootWindow(winPtr->display, winPtr->screenNum);
        !          1042:     event.xcrossing.time = TkCurrentTime(winPtr->dispPtr);
        !          1043:     XQueryPointer(winPtr->display, winPtr->window, &dummy1, &dummy2,
        !          1044:            &event.xcrossing.x_root, &event.xcrossing.y_root,
        !          1045:            &dummy3, &dummy4, &event.xcrossing.state);
        !          1046:     event.xcrossing.mode = mode;
        !          1047:     event.xcrossing.focus = False;
        !          1048:     MovePointer(&event, sourcePtr, destPtr);
        !          1049: }
        !          1050: 
        !          1051: /*
        !          1052:  *----------------------------------------------------------------------
        !          1053:  *
        !          1054:  * TkGrabDeadWindow --
        !          1055:  *
        !          1056:  *     This procedure is invoked whenever a window is deleted, so that
        !          1057:  *     grab-related cleanup can be performed.
        !          1058:  *
        !          1059:  * Results:
        !          1060:  *     None.
        !          1061:  *
        !          1062:  * Side effects:
        !          1063:  *     Various cleanups happen, such as generating events to move the
        !          1064:  *     pointer back to its "natural" window as if an ungrab had been
        !          1065:  *     done.  See the code.
        !          1066:  *
        !          1067:  *----------------------------------------------------------------------
        !          1068:  */
        !          1069: 
        !          1070: void
        !          1071: TkGrabDeadWindow(winPtr)
        !          1072:     register TkWindow *winPtr;         /* Window that is in the process
        !          1073:                                         * of being deleted. */
        !          1074: {
        !          1075:     TkDisplay *dispPtr = winPtr->dispPtr;
        !          1076: 
        !          1077:     if (dispPtr->grabWinPtr == winPtr) {
        !          1078:        dispPtr->grabWinPtr = NULL;
        !          1079:        if (!(dispPtr->grabFlags & GRAB_GLOBAL)) {
        !          1080:            /*
        !          1081:             * Must generate enter/leave events to move back to the window
        !          1082:             * that contains the mouse pointer.  We needn't filter events
        !          1083:             * here like we do in Tk_Ungrab because there are no children
        !          1084:             * of the grab window left in existence.
        !          1085:             */
        !          1086: 
        !          1087:            movePointerBack:
        !          1088:            if ((dispPtr->ungrabWinPtr != NULL)
        !          1089:                    && (dispPtr->ungrabWinPtr->mainPtr != winPtr->mainPtr)) {
        !          1090:                dispPtr->ungrabWinPtr = NULL;
        !          1091:            }
        !          1092:            MovePointer2(winPtr, dispPtr->ungrabWinPtr, NotifyUngrab);
        !          1093:        }
        !          1094:     } else if (dispPtr->buttonWinPtr == winPtr) {
        !          1095:        /*
        !          1096:         * The window in which a button was pressed was deleted.  Simulate
        !          1097:         * dropping the button auto-grab by generating Enter and Leave
        !          1098:         * events to move the pointer back to the window it's really on
        !          1099:         * top of.
        !          1100:         */
        !          1101: 
        !          1102:        dispPtr->buttonWinPtr = NULL;
        !          1103:        goto movePointerBack;
        !          1104:     }
        !          1105:     if (dispPtr->ungrabWinPtr == winPtr) {
        !          1106:        dispPtr->ungrabWinPtr = NULL;
        !          1107:     }
        !          1108:     if (dispPtr->pointerWinPtr == winPtr) {
        !          1109:        dispPtr->pointerWinPtr = NULL;
        !          1110:     }
        !          1111:     if (dispPtr->serverWinPtr == winPtr) {
        !          1112:        dispPtr->serverWinPtr = NULL;
        !          1113:     }
        !          1114: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.