Annotation of micropolis/src/tk/tkevent.c, revision 1.1.1.1

1.1       root        1: /* 
                      2:  * tkEvent.c --
                      3:  *
                      4:  *     This file provides basic event-managing facilities,
                      5:  *     whereby procedure callbacks may be attached to
                      6:  *     certain events.
                      7:  *
                      8:  * Copyright 1990-1992 Regents of the University of California.
                      9:  * Permission to use, copy, modify, and distribute this
                     10:  * software and its documentation for any purpose and without
                     11:  * fee is hereby granted, provided that the above copyright
                     12:  * notice appear in all copies.  The University of California
                     13:  * makes no representations about the suitability of this
                     14:  * software for any purpose.  It is provided "as is" without
                     15:  * express or implied warranty.
                     16:  */
                     17: 
                     18: #ifndef lint
                     19: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkEvent.c,v 1.60 92/08/21 16:15:57 ouster Exp $ SPRITE (Berkeley)";
                     20: #endif
                     21: 
                     22: #include "tkconfig.h"
                     23: #include "tkint.h"
                     24: #include <errno.h>
                     25: #include <signal.h>
                     26: #include <sys/time.h>
                     27: #include <assert.h>
                     28: 
                     29: 
                     30: /*
                     31:  * For each timer callback that's pending, there is one record
                     32:  * of the following type, chained together in a list sorted by
                     33:  * time (earliest event first).
                     34:  */
                     35: 
                     36: typedef struct TimerEvent {
                     37:     struct timeval time;       /* When timer is to fire. */
                     38:     void (*proc)  _ANSI_ARGS_((ClientData clientData));
                     39:                                /* Procedure to call. */
                     40:     ClientData clientData;     /* Argument to pass to proc. */
                     41:     Tk_TimerToken token;       /* Identifies event so it can be
                     42:                                 * deleted. */
                     43:     struct TimerEvent *nextPtr;        /* Next event in queue, or NULL for
                     44:                                 * end of queue. */
                     45: } TimerEvent;
                     46: 
                     47: static TimerEvent *timerQueue; /* First event in queue. */
                     48: 
                     49: /*
                     50:  * The information below is used to provide read, write, and
                     51:  * exception masks to select during calls to Tk_DoOneEvent.
                     52:  */
                     53: 
                     54: static int readCount;          /* Number of files for which we */
                     55: static int writeCount;         /* care about each event type. */
                     56: static int exceptCount;
                     57: #define MASK_SIZE ((OPEN_MAX+(8*sizeof(int))-1)/(8*sizeof(int)))
                     58: static int masks[3*MASK_SIZE]; /* Integer array containing official
                     59:                                 * copies of the three sets of
                     60:                                 * masks. */
                     61: static int ready[3*MASK_SIZE]; /* Temporary copy of masks, passed
                     62:                                 * to select and modified by kernel
                     63:                                 * to indicate which files are
                     64:                                 * actually ready. */
                     65: static int *readPtr;           /* Pointers to the portions of */
                     66: static int *writePtr;          /* *readyPtr for reading, writing, */
                     67: static int *exceptPtr;         /* and excepting.  Will be NULL if
                     68:                                 * corresponding count (e.g. readCount
                     69:                                 * is zero. */
                     70: static int numFds = 0;         /* Number of valid bits in mask
                     71:                                 * arrays (this value is passed
                     72:                                 * to select). */
                     73: 
                     74: /*
                     75:  * For each file registered in a call to Tk_CreateFileHandler,
                     76:  * and for each display that's currently active, there is one
                     77:  * record of the following type.  All of these records are
                     78:  * chained together into a single list.
                     79:  */
                     80: 
                     81: typedef struct FileEvent {
                     82:     int fd;                    /* Descriptor number for this file. */
                     83:     int *readPtr;              /* Pointer to word in ready array
                     84:                                 * for this file's read mask bit. */
                     85:     int *writePtr;             /* Same for write mask bit. */
                     86:     int *exceptPtr;            /* Same for except mask bit. */
                     87:     int mask;                  /* Value to AND with mask word to
                     88:                                 * select just this file's bit. */
                     89:     void (*proc)  _ANSI_ARGS_((ClientData clientData, int mask));
                     90:                                /* Procedure to call.  NULL means
                     91:                                 * this is a display. */
                     92:     ClientData clientData;     /* Argument to pass to proc.  For
                     93:                                 * displays, this is a (Display *). */
                     94:     struct FileEvent *nextPtr; /* Next in list of all files we
                     95:                                 * care about (NULL for end of
                     96:                                 * list). */
                     97: } FileEvent;
                     98: 
                     99: static FileEvent *fileList;    /* List of all file events. */
                    100: 
                    101: /*
                    102:  * There is one of the following structures for each of the
                    103:  * handlers declared in a call to Tk_DoWhenIdle.  All of the
                    104:  * currently-active handlers are linked together into a list.
                    105:  */
                    106: 
                    107: typedef struct IdleHandler {
                    108:     void (*proc)  _ANSI_ARGS_((ClientData clientData));
                    109:                                /* Procedure to call. */
                    110:     ClientData clientData;     /* Value to pass to proc. */
                    111:     struct IdleHandler *nextPtr;/* Next in list of active handlers. */
                    112: } IdleHandler;
                    113: 
                    114: static IdleHandler *idleList = NULL;
                    115:                                /* First in list of all idle handlers. */
                    116: static IdleHandler *lastIdlePtr = NULL;
                    117:                                /* Last in list (or NULL for empty list). */
                    118: 
                    119: /*
                    120:  * There's a potential problem if a handler is deleted while it's
                    121:  * current (i.e. its procedure is executing), since Tk_HandleEvent
                    122:  * will need to read the handler's "nextPtr" field when the procedure
                    123:  * returns.  To handle this problem, structures of the type below
                    124:  * indicate the next handler to be processed for any (recursively
                    125:  * nested) dispatches in progress.  The nextHandler fields get
                    126:  * updated if the handlers pointed to are deleted.  Tk_HandleEvent
                    127:  * also needs to know if the entire window gets deleted;  the winPtr
                    128:  * field is set to zero if that particular window gets deleted.
                    129:  */
                    130: 
                    131: typedef struct InProgress {
                    132:     XEvent *eventPtr;           /* Event currently being handled. */
                    133:     TkWindow *winPtr;           /* Window for event.  Gets set to None if
                    134:                                  * window is deleted while event is being
                    135:                                  * handled. */
                    136:     TkEventHandler *nextHandler; /* Next handler in search. */
                    137:     struct InProgress *nextPtr;         /* Next higher nested search. */
                    138: } InProgress;
                    139: 
                    140: static InProgress *pendingPtr = NULL;
                    141:                                /* Topmost search in progress, or
                    142:                                 * NULL if none. */
                    143: 
                    144: /*
                    145:  * For each call to Tk_CreateGenericHandler, an instance of the following
                    146:  * structure will be created.  All of the active handlers are linked into a
                    147:  * list.
                    148:  */
                    149: 
                    150: typedef struct GenericHandler {
                    151:     Tk_GenericProc *proc;      /* Procedure to dispatch on all X events. */
                    152:     ClientData clientData;     /* Client data to pass to procedure. */
                    153:     int deleteFlag;            /* Flag to set when this handler is deleted. */
                    154:     struct GenericHandler *nextPtr;
                    155:                                /* Next handler in list of all generic
                    156:                                 * handlers, or NULL for end of list. */
                    157: } GenericHandler;
                    158: 
                    159: static GenericHandler *genericList = NULL;
                    160:                                /* First handler in the list, or NULL. */
                    161: static GenericHandler *lastGenericPtr = NULL;
                    162:                                /* Last handler in list. */
                    163: 
                    164: /*
                    165:  * There's a potential problem if Tk_HandleEvent is entered recursively.
                    166:  * A handler cannot be deleted physically until we have returned from
                    167:  * calling it.  Otherwise, we're looking at unallocated memory in advancing to
                    168:  * its `next' entry.  We deal with the problem by using the `delete flag' and
                    169:  * deleting handlers only when it's known that there's no handler active.
                    170:  *
                    171:  * The following variable has a non-zero value when a handler is active.
                    172:  */
                    173: 
                    174: static int genericHandlersActive = 0;
                    175: 
                    176: /*
                    177:  * Array of event masks corresponding to each X event:
                    178:  */
                    179: 
                    180: static unsigned long eventMasks[] = {
                    181:     0,
                    182:     0,
                    183:     KeyPressMask,                      /* KeyPress */
                    184:     KeyReleaseMask,                    /* KeyRelease */
                    185:     ButtonPressMask,                   /* ButtonPress */
                    186:     ButtonReleaseMask,                 /* ButtonRelease */
                    187:     PointerMotionMask|PointerMotionHintMask|ButtonMotionMask
                    188:            |Button1MotionMask|Button2MotionMask|Button3MotionMask
                    189:            |Button4MotionMask|Button5MotionMask,
                    190:                                        /* MotionNotify */
                    191:     EnterWindowMask,                   /* EnterNotify */
                    192:     LeaveWindowMask,                   /* LeaveNotify */
                    193:     FocusChangeMask,                   /* FocusIn */
                    194:     FocusChangeMask,                   /* FocusOut */
                    195:     KeymapStateMask,                   /* KeymapNotify */
                    196:     ExposureMask,                      /* Expose */
                    197:     ExposureMask,                      /* GraphicsExpose */
                    198:     ExposureMask,                      /* NoExpose */
                    199:     VisibilityChangeMask,              /* VisibilityNotify */
                    200:     SubstructureNotifyMask,            /* CreateNotify */
                    201:     StructureNotifyMask,               /* DestroyNotify */
                    202:     StructureNotifyMask,               /* UnmapNotify */
                    203:     StructureNotifyMask,               /* MapNotify */
                    204:     SubstructureRedirectMask,          /* MapRequest */
                    205:     StructureNotifyMask,               /* ReparentNotify */
                    206:     StructureNotifyMask,               /* ConfigureNotify */
                    207:     SubstructureRedirectMask,          /* ConfigureRequest */
                    208:     StructureNotifyMask,               /* GravityNotify */
                    209:     ResizeRedirectMask,                        /* ResizeRequest */
                    210:     StructureNotifyMask,               /* CirculateNotify */
                    211:     SubstructureRedirectMask,          /* CirculateRequest */
                    212:     PropertyChangeMask,                        /* PropertyNotify */
                    213:     0,                                 /* SelectionClear */
                    214:     0,                                 /* SelectionRequest */
                    215:     0,                                 /* SelectionNotify */
                    216:     ColormapChangeMask,                        /* ColormapNotify */
                    217:     0,                                 /* ClientMessage */
                    218:     0,                                 /* Mapping Notify */
                    219: };
                    220: 
                    221: /*
                    222:  * If someone has called Tk_RestrictEvents, the information below
                    223:  * keeps track of it.
                    224:  */
                    225: 
                    226: static Bool (*restrictProc)  _ANSI_ARGS_((Display *display, XEvent *eventPtr,
                    227:     char *arg));               /* Procedure to call.  NULL means no
                    228:                                 * restrictProc is currently in effect. */
                    229: static char *restrictArg;      /* Argument to pass to restrictProc. */
                    230: 
                    231: /*
                    232:  * The following array keeps track of the last TK_NEVENTS X events, for
                    233:  * memory dump analysis.  The tracing is only done if tkEventDebug is set
                    234:  * to 1.
                    235:  */
                    236: 
                    237: #define TK_NEVENTS 32
                    238: static XEvent eventTrace[TK_NEVENTS];
                    239: static int traceIndex = 0;
                    240: int tkEventDebug = 0;
                    241: 
                    242: int tkCollapseMotion = 1;
                    243: int tkMustExit = 0;
                    244: 
                    245: 
                    246: #define DefPool(type) \
                    247: type *Unused##type = NULL; \
                    248: \
                    249: type *New##type() { \
                    250:   if (Unused##type == NULL) { \
                    251:     return (type *)ckalloc(sizeof (type)); \
                    252:   } else { \
                    253:     type *ptr = Unused##type; \
                    254:     Unused##type = ptr->nextPtr; \
                    255:     return (ptr); \
                    256:   } \
                    257: } \
                    258: \
                    259: void Free##type(type *ptr) { \
                    260:   ptr->nextPtr = Unused##type; \
                    261:   Unused##type = ptr; \
                    262: }
                    263: 
                    264: DefPool(TkEventHandler)
                    265: DefPool(GenericHandler)
                    266: DefPool(FileEvent)
                    267: DefPool(TimerEvent)
                    268: DefPool(IdleHandler)
                    269: 
                    270: 
                    271: /*
                    272:  *--------------------------------------------------------------
                    273:  *
                    274:  * Tk_CreateEventHandler --
                    275:  *
                    276:  *     Arrange for a given procedure to be invoked whenever
                    277:  *     events from a given class occur in a given window.
                    278:  *
                    279:  * Results:
                    280:  *     None.
                    281:  *
                    282:  * Side effects:
                    283:  *     From now on, whenever an event of the type given by
                    284:  *     mask occurs for token and is processed by Tk_HandleEvent,
                    285:  *     proc will be called.  See the manual entry for details
                    286:  *     of the calling sequence and return value for proc.
                    287:  *
                    288:  *--------------------------------------------------------------
                    289:  */
                    290: 
                    291: void
                    292: Tk_CreateEventHandler(token, mask, proc, clientData)
                    293:     Tk_Window token;           /* Token for window in which to
                    294:                                 * create handler. */
                    295:     unsigned long mask;                /* Events for which proc should
                    296:                                 * be called. */
                    297:     Tk_EventProc *proc;                /* Procedure to call for each
                    298:                                 * selected event */
                    299:     ClientData clientData;     /* Arbitrary data to pass to proc. */
                    300: {
                    301:     register TkEventHandler *handlerPtr;
                    302:     register TkWindow *winPtr = (TkWindow *) token;
                    303:     int found;
                    304: 
                    305:     /*
                    306:      * Skim through the list of existing handlers to (a) compute the
                    307:      * overall event mask for the window (so we can pass this new
                    308:      * value to the X system) and (b) see if there's already a handler
                    309:      * declared with the same callback and clientData (if so, just
                    310:      * change the mask).  If no existing handler matches, then create
                    311:      * a new handler.
                    312:      */
                    313: 
                    314:     found = 0;
                    315:     if (winPtr->handlerList == NULL) {
                    316:        handlerPtr = (TkEventHandler *) NewTkEventHandler();
                    317:        winPtr->handlerList = handlerPtr;
                    318:        goto initHandler;
                    319:     } else {
                    320:        for (handlerPtr = winPtr->handlerList; ;
                    321:                handlerPtr = handlerPtr->nextPtr) {
                    322:            if ((handlerPtr->proc == proc)
                    323:                    && (handlerPtr->clientData == clientData)) {
                    324:                handlerPtr->mask = mask;
                    325:                found = 1;
                    326:            }
                    327:            if (handlerPtr->nextPtr == NULL) {
                    328:                break;
                    329:            }
                    330:        }
                    331:     }
                    332: 
                    333:     /*
                    334:      * Create a new handler if no matching old handler was found.
                    335:      */
                    336: 
                    337:     if (!found) {
                    338:        handlerPtr->nextPtr = NewTkEventHandler();
                    339:        handlerPtr = handlerPtr->nextPtr;
                    340:        initHandler:
                    341:        handlerPtr->mask = mask;
                    342:        handlerPtr->proc = proc;
                    343:        handlerPtr->clientData = clientData;
                    344:        handlerPtr->nextPtr = NULL;
                    345:     }
                    346: 
                    347:     /*
                    348:      * No need to call XSelectInput:  Tk always selects on all events
                    349:      * for all windows (needed to support bindings on classes and "all").
                    350:      */
                    351: }
                    352: 
                    353: /*
                    354:  *--------------------------------------------------------------
                    355:  *
                    356:  * Tk_DeleteEventHandler --
                    357:  *
                    358:  *     Delete a previously-created handler.
                    359:  *
                    360:  * Results:
                    361:  *     None.
                    362:  *
                    363:  * Side effects:
                    364:  *     If there existed a handler as described by the
                    365:  *     parameters, the handler is deleted so that proc
                    366:  *     will not be invoked again.
                    367:  *
                    368:  *--------------------------------------------------------------
                    369:  */
                    370: 
                    371: void
                    372: Tk_DeleteEventHandler(token, mask, proc, clientData)
                    373:     Tk_Window token;           /* Same as corresponding arguments passed */
                    374:     unsigned long mask;                /* previously to Tk_CreateEventHandler. */
                    375:     Tk_EventProc *proc;
                    376:     ClientData clientData;
                    377: {
                    378:     register TkEventHandler *handlerPtr;
                    379:     register InProgress *ipPtr;
                    380:     TkEventHandler *prevPtr;
                    381:     register TkWindow *winPtr = (TkWindow *) token;
                    382: 
                    383:     /*
                    384:      * Find the event handler to be deleted, or return
                    385:      * immediately if it doesn't exist.
                    386:      */
                    387: 
                    388:     for (handlerPtr = winPtr->handlerList, prevPtr = NULL; ;
                    389:            prevPtr = handlerPtr, handlerPtr = handlerPtr->nextPtr) {
                    390:        if (handlerPtr == NULL) {
                    391:            return;
                    392:        }
                    393:        if ((handlerPtr->mask == mask) && (handlerPtr->proc == proc)
                    394:                && (handlerPtr->clientData == clientData)) {
                    395:            break;
                    396:        }
                    397:     }
                    398: 
                    399:     /*
                    400:      * If Tk_HandleEvent is about to process this handler, tell it to
                    401:      * process the next one instead.
                    402:      */
                    403: 
                    404:     for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
                    405:        if (ipPtr->nextHandler == handlerPtr) {
                    406:            ipPtr->nextHandler = handlerPtr->nextPtr;
                    407:        }
                    408:     }
                    409: 
                    410:     /*
                    411:      * Free resources associated with the handler.
                    412:      */
                    413: 
                    414:     if (prevPtr == NULL) {
                    415:        winPtr->handlerList = handlerPtr->nextPtr;
                    416:     } else {
                    417:        prevPtr->nextPtr = handlerPtr->nextPtr;
                    418:     }
                    419:     (void) FreeTkEventHandler(handlerPtr);
                    420: 
                    421: 
                    422:     /*
                    423:      * No need to call XSelectInput:  Tk always selects on all events
                    424:      * for all windows (needed to support bindings on classes and "all").
                    425:      */
                    426: }
                    427: 
                    428: /*--------------------------------------------------------------
                    429:  *
                    430:  * Tk_CreateGenericHandler --
                    431:  *
                    432:  *     Register a procedure to be called on each X event, regardless
                    433:  *     of display or window.  Generic handlers are useful for capturing
                    434:  *     events that aren't associated with windows, or events for windows
                    435:  *     not managed by Tk.
                    436:  *
                    437:  * Results:
                    438:  *     None.
                    439:  *
                    440:  * Side Effects:
                    441:  *     From now on, whenever an X event is given to Tk_HandleEvent,
                    442:  *     invoke proc, giving it clientData and the event as arguments.
                    443:  *
                    444:  *--------------------------------------------------------------
                    445:  */
                    446: 
                    447: void
                    448: Tk_CreateGenericHandler(proc, clientData)
                    449:      Tk_GenericProc *proc;     /* Procedure to call on every event. */
                    450:      ClientData clientData;    /* One-word value to pass to proc. */
                    451: {
                    452:     GenericHandler *handlerPtr;
                    453:     
                    454:     handlerPtr = NewGenericHandler();
                    455:     
                    456:     handlerPtr->proc = proc;
                    457:     handlerPtr->clientData = clientData;
                    458:     handlerPtr->deleteFlag = 0;
                    459:     handlerPtr->nextPtr = NULL;
                    460:     if (genericList == NULL) {
                    461:        genericList = handlerPtr;
                    462:     } else {
                    463:        lastGenericPtr->nextPtr = handlerPtr;
                    464:     }
                    465:     lastGenericPtr = handlerPtr;
                    466: }
                    467: 
                    468: /*
                    469:  *--------------------------------------------------------------
                    470:  *
                    471:  * Tk_DeleteGenericHandler --
                    472:  *
                    473:  *     Delete a previously-created generic handler.
                    474:  *
                    475:  * Results:
                    476:  *     None.
                    477:  *
                    478:  * Side Effects:
                    479:  *     If there existed a handler as described by the parameters,
                    480:  *     that handler is logically deleted so that proc will not be
                    481:  *     invoked again.  The physical deletion happens in the event
                    482:  *     loop in Tk_HandleEvent.
                    483:  *
                    484:  *--------------------------------------------------------------
                    485:  */
                    486: 
                    487: void
                    488: Tk_DeleteGenericHandler(proc, clientData)
                    489:      Tk_GenericProc *proc;
                    490:      ClientData clientData;
                    491: {
                    492:     GenericHandler * handler;
                    493:     
                    494:     for (handler = genericList; handler; handler = handler->nextPtr) {
                    495:        if ((handler->proc == proc) && (handler->clientData == clientData)) {
                    496:            handler->deleteFlag = 1;
                    497:        }
                    498:     }
                    499: }
                    500: 
                    501: /*
                    502:  *--------------------------------------------------------------
                    503:  *
                    504:  * Tk_HandleEvent --
                    505:  *
                    506:  *     Given an event, invoke all the handlers that have
                    507:  *     been registered for the event.
                    508:  *
                    509:  * Results:
                    510:  *     None.
                    511:  *
                    512:  * Side effects:
                    513:  *     Depends on the handlers.
                    514:  *
                    515:  *--------------------------------------------------------------
                    516:  */
                    517: 
                    518: void
                    519: Tk_HandleEvent(eventPtr)
                    520:     XEvent *eventPtr;          /* Event to dispatch. */
                    521: {
                    522:     register TkEventHandler *handlerPtr;
                    523:     register GenericHandler *genericPtr;
                    524:     register GenericHandler *genPrevPtr;
                    525:     TkWindow *winPtr;
                    526:     register unsigned long mask;
                    527:     InProgress ip;
                    528:     Window handlerWindow;
                    529: 
                    530:     /* 
                    531:      * First off, invoke all the generic event handlers (those that are
                    532:      * invoked for all events).  If a generic event handler reports that
                    533:      * an event is fully processed, go no further.
                    534:      */
                    535: 
                    536:     for (genPrevPtr = NULL, genericPtr = genericList;  genericPtr != NULL; ) {
                    537:        if (genericPtr->deleteFlag) {
                    538:            if (!genericHandlersActive) {
                    539:                GenericHandler *tmpPtr;
                    540: 
                    541:                /*
                    542:                 * This handler needs to be deleted and there are no
                    543:                 * calls pending through the handler, so now is a safe
                    544:                 * time to delete it.
                    545:                 */
                    546: 
                    547:                tmpPtr = genericPtr->nextPtr;
                    548:                if (genPrevPtr == NULL) {
                    549:                    genericList = tmpPtr;
                    550:                } else {
                    551:                    genPrevPtr->nextPtr = tmpPtr;
                    552:                }
                    553:                (void) FreeGenericHandler(genericPtr);
                    554:                genericPtr = tmpPtr;
                    555:                continue;
                    556:            }
                    557:        } else {
                    558:            int done;
                    559: 
                    560:            genericHandlersActive++;
                    561:            done = (*genericPtr->proc)(genericPtr->clientData, eventPtr);
                    562:            genericHandlersActive--;
                    563:            if (done) {
                    564:                return;
                    565:            }
                    566:        }
                    567:        genPrevPtr = genericPtr;
                    568:        genericPtr = genPrevPtr->nextPtr;
                    569:     }
                    570: 
                    571:     /*
                    572:      * Events selected by StructureNotify look the same as those
                    573:      * selected by SubstructureNotify;  the only difference is
                    574:      * whether the "event" and "window" fields are the same.
                    575:      * Check it out and convert StructureNotify to
                    576:      * SubstructureNotify if necessary.
                    577:      */
                    578: 
                    579:     handlerWindow = eventPtr->xany.window;
                    580:     mask = eventMasks[eventPtr->xany.type];
                    581:     if (mask == StructureNotifyMask) {
                    582:        if (eventPtr->xmap.event != eventPtr->xmap.window) {
                    583:            mask = SubstructureNotifyMask;
                    584:            handlerWindow = eventPtr->xmap.event;
                    585:        }
                    586:     }
                    587:     if (XFindContext(eventPtr->xany.display, handlerWindow,
                    588:            tkWindowContext, (void *) &winPtr) != 0) {
                    589: 
                    590:        /*
                    591:         * There isn't a TkWindow structure for this window.
                    592:         * However, if the event is a PropertyNotify event then call
                    593:         * the selection manager (it deals beneath-the-table with
                    594:         * certain properties).
                    595:         */
                    596: 
                    597:        if (eventPtr->type == PropertyNotify) {
                    598:            TkSelPropProc(eventPtr);
                    599:        }
                    600:        return;
                    601:     }
                    602: 
                    603:     /*
                    604:      * Redirect KeyPress and KeyRelease events if input focussing
                    605:      * is happening.  Map the x and y coordinates between the two
                    606:      * windows, if possible (make both -1 if the map-from and map-to
                    607:      * windows don't share the same top-level window).
                    608:      */
                    609: 
                    610:     if (mask & (KeyPressMask|KeyReleaseMask)) {
                    611:        winPtr->dispPtr->lastEventTime = eventPtr->xkey.time;
                    612: /* XXX: FOCUS */
                    613:            if (winPtr->dispPtr->focusPtr != NULL) {
                    614:            TkWindow *focusPtr;
                    615:            int winX, winY, focusX, focusY;
                    616:     
                    617:            focusPtr = winPtr->dispPtr->focusPtr;
                    618:            if ((focusPtr->display != winPtr->display)
                    619:                    || (focusPtr->screenNum != winPtr->screenNum)) {
                    620:                eventPtr->xkey.x = -1;
                    621:                eventPtr->xkey.y = -1;
                    622:            } else {
                    623:                Tk_GetRootCoords((Tk_Window) winPtr, &winX, &winY);
                    624:                Tk_GetRootCoords((Tk_Window) focusPtr, &focusX, &focusY);
                    625:                eventPtr->xkey.x -= focusX - winX;
                    626:                eventPtr->xkey.y -= focusY - winY;
                    627:            }
                    628:            eventPtr->xkey.window = focusPtr->window;
                    629:            winPtr = focusPtr;
                    630:        }
                    631:     }
                    632: 
                    633:     /*
                    634:      * Call a grab-related procedure to do special processing on
                    635:      * pointer events.
                    636:      */
                    637: 
                    638:     if (mask & (ButtonPressMask|ButtonReleaseMask|PointerMotionMask
                    639:            |EnterWindowMask|LeaveWindowMask)) {
                    640:        if (mask & (ButtonPressMask|ButtonReleaseMask)) {
                    641:            winPtr->dispPtr->lastEventTime = eventPtr->xbutton.time;
                    642:        } else if (mask & PointerMotionMask) {
                    643:            winPtr->dispPtr->lastEventTime = eventPtr->xmotion.time;
                    644:        } else {
                    645:            winPtr->dispPtr->lastEventTime = eventPtr->xcrossing.time;
                    646:        }
                    647:        if (TkPointerEvent(eventPtr, winPtr) == 0) {
                    648:            return;
                    649:        }
                    650:     }
                    651: 
                    652:     /*
                    653:      * For events where it hasn't already been done, update the current
                    654:      * time in the display.
                    655:      */
                    656: 
                    657:     if (eventPtr->type == PropertyNotify) {
                    658:        winPtr->dispPtr->lastEventTime = eventPtr->xproperty.time;
                    659:     }
                    660: 
                    661:     /*
                    662:      * There's a potential interaction here with Tk_DeleteEventHandler.
                    663:      * Read the documentation for pendingPtr.
                    664:      */
                    665: 
                    666:     ip.eventPtr = eventPtr;
                    667:     ip.winPtr = winPtr;
                    668:     ip.nextHandler = NULL;
                    669:     ip.nextPtr = pendingPtr;
                    670:     pendingPtr = &ip;
                    671:     if (mask == 0) {
                    672:        if ((eventPtr->type == SelectionClear)
                    673:                || (eventPtr->type == SelectionRequest)
                    674:                || (eventPtr->type == SelectionNotify)) {
                    675:            TkSelEventProc((Tk_Window) winPtr, eventPtr);
                    676:        } else if ((eventPtr->type == ClientMessage)
                    677:                && (eventPtr->xclient.message_type == 
                    678:                    Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS"))) {
                    679:                /*
                    680:                 * this is a ICCCM WM_PROTOCOL ClientMessage 
                    681:                 */
                    682:                TkWmProtocolEventProc(winPtr, eventPtr);
                    683:        }
                    684:     } else {
                    685:        for (handlerPtr = winPtr->handlerList; handlerPtr != NULL; ) {
                    686:            if ((handlerPtr->mask & mask) != 0) {
                    687:                ip.nextHandler = handlerPtr->nextPtr;
                    688:                (*(handlerPtr->proc))(handlerPtr->clientData, eventPtr);
                    689:                handlerPtr = ip.nextHandler;
                    690:            } else {
                    691:                handlerPtr = handlerPtr->nextPtr;
                    692:            }
                    693:        }
                    694: 
                    695:        /*
                    696:         * Pass the event to the "bind" command mechanism.  But, don't
                    697:         * do this for SubstructureNotify events.  The "bind" command
                    698:         * doesn't support them anyway, and it's easier to filter out
                    699:         * these events here than in the lower-level procedures.
                    700:         */
                    701: 
                    702:        if ((ip.winPtr != None) && (mask != SubstructureNotifyMask)) {
                    703:            TkBindEventProc(winPtr, eventPtr);
                    704:        }
                    705:     }
                    706:     pendingPtr = ip.nextPtr;
                    707: }
                    708: 
                    709: /*
                    710:  *--------------------------------------------------------------
                    711:  *
                    712:  * Tk_CreateFileHandler --
                    713:  *
                    714:  *     Arrange for a given procedure to be invoked whenever
                    715:  *     a given file becomes readable or writable.
                    716:  *
                    717:  * Results:
                    718:  *     None.
                    719:  *
                    720:  * Side effects:
                    721:  *     From now on, whenever the I/O channel given by fd becomes
                    722:  *     ready in the way indicated by mask, proc will be invoked.
                    723:  *     See the manual entry for details on the calling sequence
                    724:  *     to proc.  If fd is already registered then the old mask
                    725:  *     and proc and clientData values will be replaced with
                    726:  *     new ones.
                    727:  *
                    728:  *--------------------------------------------------------------
                    729:  */
                    730: 
                    731: void
                    732: Tk_CreateFileHandler(fd, mask, proc, clientData)
                    733:     int fd;                    /* Integer identifier for stream. */
                    734:     int mask;                  /* OR'ed combination of TK_READABLE,
                    735:                                 * TK_WRITABLE, and TK_EXCEPTION:
                    736:                                 * indicates conditions under which
                    737:                                 * proc should be called. */
                    738:     Tk_FileProc *proc;         /* Procedure to call for each
                    739:                                 * selected event.  NULL means that
                    740:                                 * this is a display, and that
                    741:                                 * clientData is the (Display *)
                    742:                                 * for it, and that events should
                    743:                                 * be handled automatically. */
                    744:     ClientData clientData;     /* Arbitrary data to pass to proc. */
                    745: {
                    746:     register FileEvent *filePtr;
                    747:     int index;
                    748: 
                    749:     if (fd >= OPEN_MAX) {
                    750:        panic("Tk_CreatefileHandler can't handle file id %d", fd);
                    751:     }
                    752: 
                    753:     /*
                    754:      * Make sure the file isn't already registered.  Create a
                    755:      * new record in the normal case where there's no existing
                    756:      * record.
                    757:      */
                    758: 
                    759:     for (filePtr = fileList; filePtr != NULL;
                    760:            filePtr = filePtr->nextPtr) {
                    761:        if (filePtr->fd == fd) {
                    762:            break;
                    763:        }
                    764:     }
                    765:     index = fd/(8*sizeof(int));
                    766:     if (filePtr == NULL) {
                    767:        filePtr = NewFileEvent();
                    768:        filePtr->fd = fd;
                    769:        filePtr->readPtr = &ready[index];
                    770:        filePtr->writePtr = &ready[index+MASK_SIZE];
                    771:        filePtr->exceptPtr = &ready[index+2*MASK_SIZE];
                    772:        filePtr->mask = 1 << (fd%(8*sizeof(int)));
                    773:        filePtr->nextPtr = fileList;
                    774:        fileList = filePtr;
                    775:     } else {
                    776:        if (masks[index] & filePtr->mask) {
                    777:            readCount--;
                    778:            *filePtr->readPtr &= ~filePtr->mask;
                    779:            masks[index] &= ~filePtr->mask;
                    780:        }
                    781:        if (masks[index+MASK_SIZE] & filePtr->mask) {
                    782:            writeCount--;
                    783:            *filePtr->writePtr &= ~filePtr->mask;
                    784:            masks[index+MASK_SIZE] &= ~filePtr->mask;
                    785:        }
                    786:        if (masks[index+2*MASK_SIZE] & filePtr->mask) {
                    787:            exceptCount--;
                    788:            *filePtr->exceptPtr &= ~filePtr->mask;
                    789:            masks[index+2*MASK_SIZE] &= ~filePtr->mask;
                    790:        }
                    791:     }
                    792: 
                    793:     /*
                    794:      * The remainder of the initialization below is done
                    795:      * regardless of whether or not this is a new record
                    796:      * or a modification of an old one.
                    797:      */
                    798: 
                    799:     if (mask & TK_READABLE) {
                    800:        masks[index] |= filePtr->mask;
                    801:        readCount++;
                    802:     }
                    803:     readPtr = (readCount == 0 ? NULL : &ready[0]);
                    804: 
                    805:     if (mask & TK_WRITABLE) {
                    806:        masks[index+MASK_SIZE] |= filePtr->mask;
                    807:        writeCount++;
                    808:     }
                    809:     writePtr = (writeCount == 0 ? NULL : &ready[MASK_SIZE]);
                    810: 
                    811:     if (mask & TK_EXCEPTION) {
                    812:        masks[index+2*MASK_SIZE] |= filePtr->mask;
                    813:        exceptCount++;
                    814:     }
                    815:     exceptPtr = (exceptCount == 0 ? NULL : &ready[2*MASK_SIZE]);
                    816: 
                    817:     filePtr->proc = proc;
                    818:     filePtr->clientData = clientData;
                    819: 
                    820:     if (numFds <= fd) {
                    821:        numFds = fd+1;
                    822:     }
                    823: }
                    824: 
                    825: /*
                    826:  *--------------------------------------------------------------
                    827:  *
                    828:  * Tk_DeleteFileHandler --
                    829:  *
                    830:  *     Cancel a previously-arranged callback arrangement for
                    831:  *     a file.
                    832:  *
                    833:  * Results:
                    834:  *     None.
                    835:  *
                    836:  * Side effects:
                    837:  *     If a callback was previously registered on fd, remove it.
                    838:  *
                    839:  *--------------------------------------------------------------
                    840:  */
                    841: 
                    842: void
                    843: Tk_DeleteFileHandler(fd)
                    844:     int fd;                    /* Stream id for which to remove
                    845:                                 * callback procedure. */
                    846: {
                    847:     register FileEvent *filePtr;
                    848:     FileEvent *prevPtr;
                    849:     int index;
                    850: 
                    851:     /*
                    852:      * Find the entry for the given file (and return if there
                    853:      * isn't one).
                    854:      */
                    855: 
                    856:     for (prevPtr = NULL, filePtr = fileList; ;
                    857:            prevPtr = filePtr, filePtr = filePtr->nextPtr) {
                    858:        if (filePtr == NULL) {
                    859:            return;
                    860:        }
                    861:        if (filePtr->fd == fd) {
                    862:            break;
                    863:        }
                    864:     }
                    865: 
                    866:     /*
                    867:      * Clean up information in the callback record.
                    868:      */
                    869: 
                    870:     index = filePtr->fd/(8*sizeof(int));
                    871:     if (masks[index] & filePtr->mask) {
                    872:        readCount--;
                    873:        *filePtr->readPtr &= ~filePtr->mask;
                    874:        masks[index] &= ~filePtr->mask;
                    875:     }
                    876:     if (masks[index+MASK_SIZE] & filePtr->mask) {
                    877:        writeCount--;
                    878:        *filePtr->writePtr &= ~filePtr->mask;
                    879:        masks[index+MASK_SIZE] &= ~filePtr->mask;
                    880:     }
                    881:     if (masks[index+2*MASK_SIZE] & filePtr->mask) {
                    882:        exceptCount--;
                    883:        *filePtr->exceptPtr &= ~filePtr->mask;
                    884:        masks[index+2*MASK_SIZE] &= ~filePtr->mask;
                    885:     }
                    886:     if (prevPtr == NULL) {
                    887:        fileList = filePtr->nextPtr;
                    888:     } else {
                    889:        prevPtr->nextPtr = filePtr->nextPtr;
                    890:     }
                    891:     FreeFileEvent(filePtr);
                    892: 
                    893:     /*
                    894:      * Recompute numFds.
                    895:      */
                    896: 
                    897:     numFds = 0;
                    898:     for (filePtr = fileList; filePtr != NULL;
                    899:            filePtr = filePtr->nextPtr) {
                    900:        if (numFds <= filePtr->fd) {
                    901:            numFds = filePtr->fd+1;
                    902:        }
                    903:     }
                    904: }
                    905: 
                    906: /*
                    907:  *--------------------------------------------------------------
                    908:  *
                    909:  * Tk_CreateTimerHandler --
                    910:  *
                    911:  *     Arrange for a given procedure to be invoked at a particular
                    912:  *     time in the future.
                    913:  *
                    914:  * Results:
                    915:  *     The return value is a token for the timer event, which
                    916:  *     may be used to delete the event before it fires.
                    917:  *
                    918:  * Side effects:
                    919:  *     When milliseconds have elapsed, proc will be invoked
                    920:  *     exactly once.
                    921:  *
                    922:  *--------------------------------------------------------------
                    923:  */
                    924: 
                    925: Tk_TimerToken
                    926: Tk_CreateTimerHandler(milliseconds, proc, clientData)
                    927:     int milliseconds;          /* How many milliseconds to wait
                    928:                                 * before invoking proc. */
                    929:     Tk_TimerProc *proc;                /* Procedure to invoke. */
                    930:     ClientData clientData;     /* Arbitrary data to pass to proc. */
                    931: {
                    932:     register TimerEvent *timerPtr, *tPtr2, *prevPtr;
                    933:     static int id = 0;
                    934: 
                    935:     timerPtr = NewTimerEvent();
                    936: 
                    937:     /*
                    938:      * Compute when the event should fire.
                    939:      */
                    940: 
                    941:     (void) gettimeofday(&timerPtr->time, (struct timezone *) NULL);
                    942:     timerPtr->time.tv_sec += milliseconds/1000;
                    943:     timerPtr->time.tv_usec += (milliseconds%1000)*1000;
                    944:     if (timerPtr->time.tv_usec > 1000000) {
                    945:        timerPtr->time.tv_usec -= 1000000;
                    946:        timerPtr->time.tv_sec += 1;
                    947:     }
                    948: 
                    949:     /*
                    950:      * Fill in other fields for the event.
                    951:      */
                    952: 
                    953:     timerPtr->proc = proc;
                    954:     timerPtr->clientData = clientData;
                    955:     id++;
                    956:     timerPtr->token = (Tk_TimerToken) id;
                    957: 
                    958:     /*
                    959:      * Add the event to the queue in the correct position
                    960:      * (ordered by event firing time).
                    961:      */
                    962: 
                    963:     for (tPtr2 = timerQueue, prevPtr = NULL; tPtr2 != NULL;
                    964:            prevPtr = tPtr2, tPtr2 = tPtr2->nextPtr) {
                    965:        if ((tPtr2->time.tv_sec > timerPtr->time.tv_sec)
                    966:                || ((tPtr2->time.tv_sec == timerPtr->time.tv_sec)
                    967:                && (tPtr2->time.tv_usec > timerPtr->time.tv_usec))) {
                    968:            break;
                    969:        }
                    970:     }
                    971:     if (prevPtr == NULL) {
                    972:        timerPtr->nextPtr = timerQueue;
                    973:        timerQueue = timerPtr;
                    974:     } else {
                    975:        timerPtr->nextPtr = prevPtr->nextPtr;
                    976:        prevPtr->nextPtr = timerPtr;
                    977:     }
                    978:     return timerPtr->token;
                    979: }
                    980: 
                    981: // Added by Don to support finer timer resolution.
                    982: /*
                    983:  *--------------------------------------------------------------
                    984:  *
                    985:  * Tk_CreateMicroTimerHandler --
                    986:  *
                    987:  *     Arrange for a given procedure to be invoked at a particular
                    988:  *     time in the future.
                    989:  *
                    990:  * Results:
                    991:  *     The return value is a token for the timer event, which
                    992:  *     may be used to delete the event before it fires.
                    993:  *
                    994:  * Side effects:
                    995:  *     When seconds and seconds have elapsed, proc will be invoked
                    996:  *     exactly once.
                    997:  *
                    998:  *--------------------------------------------------------------
                    999:  */
                   1000: 
                   1001: Tk_TimerToken
                   1002: Tk_CreateMicroTimerHandler(seconds, microseconds, proc, clientData)
                   1003:     int seconds;               /* How many seconds to wait
                   1004:                                 * before invoking proc. */
                   1005:     int microseconds;          /* How many microseconds to wait
                   1006:                                 * before invoking proc. */
                   1007:     Tk_TimerProc *proc;                /* Procedure to invoke. */
                   1008:     ClientData clientData;     /* Arbitrary data to pass to proc. */
                   1009: {
                   1010:     register TimerEvent *timerPtr, *tPtr2, *prevPtr;
                   1011:     static int id = 0;
                   1012: 
                   1013:     timerPtr = NewTimerEvent();
                   1014: 
                   1015:     /*
                   1016:      * Compute when the event should fire.
                   1017:      */
                   1018: 
                   1019:     (void) gettimeofday(&timerPtr->time, (struct timezone *) NULL);
                   1020:     timerPtr->time.tv_sec += seconds;
                   1021:     timerPtr->time.tv_usec += microseconds;
                   1022:     while (timerPtr->time.tv_usec > 1000000) {
                   1023:        timerPtr->time.tv_usec -= 1000000;
                   1024:        timerPtr->time.tv_sec += 1;
                   1025:     }
                   1026: 
                   1027:     /*
                   1028:      * Fill in other fields for the event.
                   1029:      */
                   1030: 
                   1031:     timerPtr->proc = proc;
                   1032:     timerPtr->clientData = clientData;
                   1033:     id++;
                   1034:     timerPtr->token = (Tk_TimerToken) id;
                   1035: 
                   1036:     /*
                   1037:      * Add the event to the queue in the correct position
                   1038:      * (ordered by event firing time).
                   1039:      */
                   1040: 
                   1041:     for (tPtr2 = timerQueue, prevPtr = NULL; tPtr2 != NULL;
                   1042:            prevPtr = tPtr2, tPtr2 = tPtr2->nextPtr) {
                   1043:        if ((tPtr2->time.tv_sec > timerPtr->time.tv_sec)
                   1044:                || ((tPtr2->time.tv_sec == timerPtr->time.tv_sec)
                   1045:                && (tPtr2->time.tv_usec > timerPtr->time.tv_usec))) {
                   1046:            break;
                   1047:        }
                   1048:     }
                   1049:     if (prevPtr == NULL) {
                   1050:        timerPtr->nextPtr = timerQueue;
                   1051:        timerQueue = timerPtr;
                   1052:     } else {
                   1053:        timerPtr->nextPtr = prevPtr->nextPtr;
                   1054:        prevPtr->nextPtr = timerPtr;
                   1055:     }
                   1056:     return timerPtr->token;
                   1057: }
                   1058: 
                   1059: 
                   1060: /*
                   1061:  *--------------------------------------------------------------
                   1062:  *
                   1063:  * Tk_DeleteTimerHandler --
                   1064:  *
                   1065:  *     Delete a previously-registered timer handler.
                   1066:  *
                   1067:  * Results:
                   1068:  *     None.
                   1069:  *
                   1070:  * Side effects:
                   1071:  *     Destroy the timer callback identified by TimerToken,
                   1072:  *     so that its associated procedure will not be called.
                   1073:  *     If the callback has already fired, or if the given
                   1074:  *     token doesn't exist, then nothing happens.
                   1075:  *
                   1076:  *--------------------------------------------------------------
                   1077:  */
                   1078: 
                   1079: void
                   1080: Tk_DeleteTimerHandler(token)
                   1081:     Tk_TimerToken token;       /* Result previously returned by
                   1082:                                 * Tk_DeleteTimerHandler. */
                   1083: {
                   1084:     register TimerEvent *timerPtr, *prevPtr;
                   1085: 
                   1086:     if (token == 0) return;
                   1087: 
                   1088:     for (timerPtr = timerQueue, prevPtr = NULL; timerPtr != NULL;
                   1089:            prevPtr = timerPtr, timerPtr = timerPtr->nextPtr) {
                   1090:        if (timerPtr->token != token) {
                   1091:            continue;
                   1092:        }
                   1093:        if (prevPtr == NULL) {
                   1094:            timerQueue = timerPtr->nextPtr;
                   1095:        } else {
                   1096:            prevPtr->nextPtr = timerPtr->nextPtr;
                   1097:        }
                   1098:        FreeTimerEvent(timerPtr);
                   1099:        return;
                   1100:     }
                   1101: 
                   1102: //    fprintf(stderr, "Tk_DeleteTimerHandler called on bogus timer %d\n", token);
                   1103: }
                   1104: 
                   1105: /*
                   1106:  *--------------------------------------------------------------
                   1107:  *
                   1108:  * Tk_DoWhenIdle --
                   1109:  *
                   1110:  *     Arrange for proc to be invoked the next time the
                   1111:  *     system is idle (i.e., just before the next time
                   1112:  *     that Tk_DoOneEvent would have to wait for something
                   1113:  *     to happen).
                   1114:  *
                   1115:  * Results:
                   1116:  *     None.
                   1117:  *
                   1118:  * Side effects:
                   1119:  *     Proc will eventually be called, with clientData
                   1120:  *     as argument.  See the manual entry for details.
                   1121:  *
                   1122:  *--------------------------------------------------------------
                   1123:  */
                   1124: 
                   1125: void
                   1126: Tk_DoWhenIdle(proc, clientData)
                   1127:     Tk_IdleProc *proc;         /* Procedure to invoke. */
                   1128:     ClientData clientData;     /* Arbitrary value to pass to proc. */
                   1129: {
                   1130:     register IdleHandler *idlePtr;
                   1131: 
                   1132:     idlePtr = NewIdleHandler();
                   1133:     idlePtr->proc = proc;
                   1134:     idlePtr->clientData = clientData;
                   1135:     idlePtr->nextPtr = NULL;
                   1136:     if (lastIdlePtr == NULL) {
                   1137:        idleList = idlePtr;
                   1138:     } else {
                   1139:        lastIdlePtr->nextPtr = idlePtr;
                   1140:     }
                   1141:     lastIdlePtr = idlePtr;
                   1142: }
                   1143: 
                   1144: /*
                   1145:  *----------------------------------------------------------------------
                   1146:  *
                   1147:  * Tk_CancelIdleCall --
                   1148:  *
                   1149:  *     If there are any when-idle calls requested to a given procedure
                   1150:  *     with given clientData, cancel all of them.
                   1151:  *
                   1152:  * Results:
                   1153:  *     None.
                   1154:  *
                   1155:  * Side effects:
                   1156:  *     If the proc/clientData combination were on the when-idle list,
                   1157:  *     they are removed so that they will never be called.
                   1158:  *
                   1159:  *----------------------------------------------------------------------
                   1160:  */
                   1161: 
                   1162: void
                   1163: Tk_CancelIdleCall(proc, clientData)
                   1164:     Tk_IdleProc *proc;         /* Procedure that was previously registered. */
                   1165:     ClientData clientData;     /* Arbitrary value to pass to proc. */
                   1166: {
                   1167:     register IdleHandler *idlePtr, *prevPtr;
                   1168:     IdleHandler *nextPtr;
                   1169: 
                   1170:     for (prevPtr = NULL, idlePtr = idleList; idlePtr != NULL;
                   1171:            prevPtr = idlePtr, idlePtr = idlePtr->nextPtr) {
                   1172:        while ((idlePtr->proc == proc)
                   1173:                && (idlePtr->clientData == clientData)) {
                   1174:            nextPtr = idlePtr->nextPtr;
                   1175:            FreeIdleHandler(idlePtr);
                   1176:            idlePtr = nextPtr;
                   1177:            if (prevPtr == NULL) {
                   1178:                idleList = idlePtr;
                   1179:            } else {
                   1180:                prevPtr->nextPtr = idlePtr;
                   1181:            }
                   1182:            if (idlePtr == NULL) {
                   1183:                lastIdlePtr = prevPtr;
                   1184:                return;
                   1185:            }
                   1186:        }
                   1187:     }
                   1188: }
                   1189: 
                   1190: /*
                   1191:  *--------------------------------------------------------------
                   1192:  *
                   1193:  * Tk_DoOneEvent --
                   1194:  *
                   1195:  *     Process a single event of some sort.  If there's no
                   1196:  *     work to do, wait for an event to occur, then process
                   1197:  *     it.
                   1198:  *
                   1199:  * Results:
                   1200:  *     The return value is 1 if the procedure actually found
                   1201:  *     an event to process.  If no event was found then 0 is
                   1202:  *     returned.
                   1203:  *
                   1204:  * Side effects:
                   1205:  *     May delay execution of process while waiting for an
                   1206:  *     X event, X error, file-ready event, or timer event.
                   1207:  *     The handling of the event could cause additional
                   1208:  *     side effects.  Collapses sequences of mouse-motion
                   1209:  *     events for the same window into a single event by
                   1210:  *     delaying motion event processing.
                   1211:  *
                   1212:  *--------------------------------------------------------------
                   1213:  */
                   1214: 
                   1215: int
                   1216: Tk_DoOneEvent(flags)
                   1217:     int flags;                 /* Miscellaneous flag values:  may be any
                   1218:                                 * combination of TK_DONT_WAIT, TK_X_EVENTS,
                   1219:                                 * TK_FILE_EVENTS, TK_TIMER_EVENTS, and
                   1220:                                 * TK_IDLE_EVENTS. */
                   1221: {
                   1222:     register FileEvent *filePtr;
                   1223:     struct timeval curTime, timeout, *timeoutPtr;
                   1224:     int numFound;
                   1225:     static XEvent delayedMotionEvent;  /* Used to hold motion events that
                   1226:                                         * are being saved until later. */
                   1227:     static int eventDelayed = 0;       /* Non-zero means there is an event
                   1228:                                         * in delayedMotionEvent. */
                   1229: 
                   1230:     if ((flags & TK_ALL_EVENTS) == 0) {
                   1231:        flags |= TK_ALL_EVENTS;
                   1232:     }
                   1233: 
                   1234:     /*
                   1235:      * Phase One: see if there's already something ready
                   1236:      * (either a file or a display) that was left over
                   1237:      * from before (i.e don't do a select, just check the
                   1238:      * bits from the last select).
                   1239:      */
                   1240: 
                   1241:     checkFiles:
                   1242:     for (filePtr = fileList; filePtr != NULL;
                   1243:            filePtr = filePtr->nextPtr) {
                   1244:        int mask;
                   1245: 
                   1246:        /*
                   1247:         * Displays:  flush output, check for queued events,
                   1248:         * and read events from the server if display is ready.
                   1249:         * If there are any events, process one and then
                   1250:         * return.
                   1251:         */
                   1252: 
                   1253:        if ((filePtr->proc == NULL) && (flags & TK_X_EVENTS)) {
                   1254:            Display *display = (Display *) filePtr->clientData;
                   1255:            XEvent event;
                   1256: 
                   1257:            XFlush(display);
                   1258:            if ((*filePtr->readPtr) & filePtr->mask) {
                   1259:                *filePtr->readPtr &= ~filePtr->mask;
                   1260:                if (XEventsQueued(display, QueuedAfterReading) == 0) {
                   1261: 
                   1262:                    /*
                   1263:                     * Things are very tricky if there aren't any events
                   1264:                     * readable at this point (after all, there was
                   1265:                     * supposedly data available on the connection).
                   1266:                     * A couple of things could have occurred:
                   1267:                     * 
                   1268:                     * One possibility is that there were only error events
                   1269:                     * in the input from the server.  If this happens,
                   1270:                     * we should return (we don't want to go to sleep
                   1271:                     * in XNextEvent below, since this would block out
                   1272:                     * other sources of input to the process).
                   1273:                     *
                   1274:                     * Another possibility is that our connection to the
                   1275:                     * server has been closed.  This will not necessarily
                   1276:                     * be detected in XEventsQueued (!!), so if we just
                   1277:                     * return then there will be an infinite loop.  To
                   1278:                     * detect such an error, generate a NoOp protocol
                   1279:                     * request to exercise the connection to the server,
                   1280:                     * then return.  However, must disable SIGPIPE while
                   1281:                     * sending the event, or else the process will die
                   1282:                     * from the signal and won't invoke the X error
                   1283:                     * function to print a nice message.
                   1284:                     */
                   1285: 
                   1286:                    void (*oldHandler)();
                   1287: 
                   1288:                    oldHandler = (void (*)()) signal(SIGPIPE, SIG_IGN);
                   1289:                    XNoOp(display);
                   1290:                    XFlush(display);
                   1291:                    (void) signal(SIGPIPE, oldHandler);
                   1292:                    return 1;
                   1293:                }
                   1294:                if (restrictProc != NULL) {
                   1295:                    if (!XCheckIfEvent(display, &event, restrictProc,
                   1296:                            restrictArg)) {
                   1297:                        return 1;
                   1298:                    }
                   1299:                } else {
                   1300:                    XNextEvent(display, &event);
                   1301:                }
                   1302:            } else {
                   1303:                if (QLength(display) == 0) {
                   1304:                    continue;
                   1305:                }
                   1306:                if (restrictProc != NULL) {
                   1307:                    if (!XCheckIfEvent(display, &event, restrictProc,
                   1308:                            restrictArg)) {
                   1309:                        continue;
                   1310:                    }
                   1311:                } else {
                   1312:                    XNextEvent(display, &event);
                   1313:                }
                   1314:            }
                   1315: 
                   1316:            /*
                   1317:             * Got an event.  Deal with mouse-motion-collapsing and
                   1318:             * event-delaying here.  If there's already an event delayed,
                   1319:             * then process that event if it's incompatible with the new
                   1320:             * event (new event not mouse motion, or window changed, or
                   1321:             * state changed).  If the new event is mouse motion, then
                   1322:             * don't process it now;  delay it until later in the hopes
                   1323:             * that it can be merged with other mouse motion events
                   1324:             * immediately following.
                   1325:             */
                   1326: 
                   1327:            if (tkEventDebug) {
                   1328:                eventTrace[traceIndex] = event;
                   1329:                traceIndex = (traceIndex+1) % TK_NEVENTS;
                   1330:            }
                   1331: 
                   1332:            if (eventDelayed) {
                   1333:                if (((event.type != MotionNotify)
                   1334:                            && (event.type != GraphicsExpose)
                   1335:                            && (event.type != NoExpose)
                   1336:                            && (event.type != Expose))
                   1337:                        || (event.xmotion.display
                   1338:                            != delayedMotionEvent.xmotion.display)
                   1339:                        || (event.xmotion.window
                   1340:                            != delayedMotionEvent.xmotion.window)) {
                   1341:                    XEvent copy;
                   1342: 
                   1343:                    /*
                   1344:                     * Must copy the event out of delayedMotionEvent before
                   1345:                     * processing it, in order to allow recursive calls to
                   1346:                     * Tk_DoOneEvent as part of the handler.
                   1347:                     */
                   1348: 
                   1349:                    copy = delayedMotionEvent;
                   1350:                    eventDelayed = 0;
                   1351:                    Tk_HandleEvent(&copy);
                   1352:                }
                   1353:            }
                   1354:            if (tkCollapseMotion && event.type == MotionNotify) {
                   1355:                delayedMotionEvent = event;
                   1356:                eventDelayed = 1;
                   1357:            } else {
                   1358:                Tk_HandleEvent(&event);
                   1359:            }
                   1360:            return 1;
                   1361:        }
                   1362: 
                   1363:        /*
                   1364:         * Not a display:  if the file is ready, call the
                   1365:         * appropriate handler.
                   1366:         */
                   1367: 
                   1368:        if (((*filePtr->readPtr | *filePtr->writePtr
                   1369:                | *filePtr->exceptPtr) & filePtr->mask) == 0) {
                   1370:            continue;
                   1371:        }
                   1372:        if (!(flags & TK_FILE_EVENTS)) {
                   1373:            continue;
                   1374:        }
                   1375:        mask = 0;
                   1376:        if (*filePtr->readPtr & filePtr->mask) {
                   1377:            mask |= TK_READABLE;
                   1378:            *filePtr->readPtr &= ~filePtr->mask;
                   1379:        }
                   1380:        if (*filePtr->writePtr & filePtr->mask) {
                   1381:            mask |= TK_WRITABLE;
                   1382:            *filePtr->writePtr &= ~filePtr->mask;
                   1383:        }
                   1384:        if (*filePtr->exceptPtr & filePtr->mask) {
                   1385:            mask |= TK_EXCEPTION;
                   1386:            *filePtr->exceptPtr &= ~filePtr->mask;
                   1387:        }
                   1388:        (*filePtr->proc)(filePtr->clientData, mask);
                   1389:        return 1;
                   1390:     }
                   1391: 
                   1392:     /*
                   1393:      * Phase Two: get the current time and see if any timer
                   1394:      * events are ready to fire.  If so, fire one and return.
                   1395:      */
                   1396: 
                   1397:     checkTime:
                   1398:     if ((timerQueue != NULL) && (flags & TK_TIMER_EVENTS)) {
                   1399:        register TimerEvent *timerPtr = timerQueue;
                   1400: 
                   1401:        (void) gettimeofday(&curTime, (struct timezone *) NULL);
                   1402:        if ((timerPtr->time.tv_sec < curTime.tv_sec)
                   1403:                || ((timerPtr->time.tv_sec == curTime.tv_sec)
                   1404:                &&  (timerPtr->time.tv_usec < curTime.tv_usec))) {
                   1405:            timerQueue = timerPtr->nextPtr;
                   1406:            (*timerPtr->proc)(timerPtr->clientData);
                   1407:            FreeTimerEvent(timerPtr);
                   1408:            return 1;
                   1409:        }
                   1410:     }
                   1411: 
                   1412: 
                   1413:     /*
                   1414:      * Phase Three: if there is a delayed motion event, process it
                   1415:      * now, before any DoWhenIdle handlers.  Better to process before
                   1416:      * idle handlers than after, because the goal of idle handlers is
                   1417:      * to delay until after all pending events have been processed.
                   1418:      * Must free up delayedMotionEvent *before* calling Tk_HandleEvent,
                   1419:      * so that the event handler can call Tk_DoOneEvent recursively
                   1420:      * without infinite looping.
                   1421:      */
                   1422: 
                   1423:     if ((eventDelayed) && (flags & TK_X_EVENTS)) {
                   1424:        XEvent copy;
                   1425: 
                   1426:        copy = delayedMotionEvent;
                   1427:        eventDelayed = 0;
                   1428:        Tk_HandleEvent(&copy);
                   1429:        return 1;
                   1430:     }
                   1431: 
                   1432:     /*
                   1433:      * Phase Four: if there are DoWhenIdle requests pending (or
                   1434:      * if we're not allowed to block), then do a select with an
                   1435:      * instantaneous timeout.  If a ready file is found, then go
                   1436:      * back to process it.
                   1437:      */
                   1438: 
                   1439:     if (((idleList != NULL) && (flags & TK_IDLE_EVENTS))
                   1440:            || (flags & TK_DONT_WAIT)) {
                   1441:        if (flags & (TK_X_EVENTS|TK_FILE_EVENTS)) {
                   1442:            memcpy((VOID *) ready, (VOID *) masks, 3*MASK_SIZE*sizeof(int));
                   1443:            timeout.tv_sec = timeout.tv_usec = 0;
                   1444:            do {
                   1445:                numFound = select(numFds, (SELECT_MASK *) readPtr,
                   1446:                        (SELECT_MASK *) writePtr, (SELECT_MASK *) exceptPtr,
                   1447:                    &timeout);
                   1448:            } while ((numFound == -1) && (errno == EINTR));
                   1449:            if (numFound > 0) {
                   1450:                goto checkFiles;
                   1451:            }
                   1452:        }
                   1453:     }
                   1454: 
                   1455:     /*
                   1456:      * Phase Five:  process all pending DoWhenIdle requests.
                   1457:      */
                   1458: 
                   1459:     if ((idleList != NULL) && (flags & TK_IDLE_EVENTS)) {
                   1460:        register IdleHandler *idlePtr;
                   1461: 
                   1462:        /*
                   1463:         * If you change the code below, be aware that new handlers
                   1464:         * can get added to the list while the current one is being
                   1465:         * processed.
                   1466:         *
                   1467:         * NOTE!  Must remove the entry from the list before calling
                   1468:         * it, in case the idle handler calls Tk_DoOneEvent:  don't
                   1469:         * want to loop infinitely.  Must also be careful because
                   1470:         * Tk_CancelIdleCall could change the list during the call.
                   1471:         */
                   1472: 
                   1473:        while (idleList != NULL) {
                   1474:            idlePtr = idleList;
                   1475:            idleList = idlePtr->nextPtr;
                   1476:            if (idleList == NULL) {
                   1477:                lastIdlePtr = NULL;
                   1478:            }
                   1479:            (*idlePtr->proc)(idlePtr->clientData);
                   1480:            FreeIdleHandler(idlePtr);
                   1481:        }
                   1482:        return 1;
                   1483:     }
                   1484: 
                   1485:     /*
                   1486:      * Phase Six: do a select to wait for either one of the
                   1487:      * files to become ready or for the first timer event to
                   1488:      * fire.  Then go back to process the event.
                   1489:      */
                   1490: 
                   1491:     if ((flags & TK_DONT_WAIT)
                   1492:            || !(flags & (TK_TIMER_EVENTS|TK_FILE_EVENTS|TK_X_EVENTS))) {
                   1493:        return 0;
                   1494:     }
                   1495:     if ((timerQueue == NULL) || !(flags & TK_TIMER_EVENTS)) {
                   1496:        timeoutPtr = NULL;
                   1497:     } else {
                   1498:        timeoutPtr = &timeout;
                   1499:        timeout.tv_sec = timerQueue->time.tv_sec - curTime.tv_sec;
                   1500:        timeout.tv_usec = timerQueue->time.tv_usec - curTime.tv_usec;
                   1501:        if (timeout.tv_usec < 0) {
                   1502:            timeout.tv_sec -= 1;
                   1503:            timeout.tv_usec += 1000000;
                   1504:        }
                   1505:     }
                   1506:     memcpy((VOID *) ready, (VOID *) masks, 3*MASK_SIZE*sizeof(int));
                   1507:     do {
                   1508:        numFound = select(numFds, (SELECT_MASK *) readPtr,
                   1509:                (SELECT_MASK *) writePtr, (SELECT_MASK *) exceptPtr,
                   1510:                timeoutPtr);
                   1511:     } while ((numFound == -1) && (errno == EINTR));
                   1512:     if (numFound == 0) {
                   1513:        goto checkTime;
                   1514:     }
                   1515:     goto checkFiles;
                   1516: }
                   1517: 
                   1518: /*
                   1519:  *--------------------------------------------------------------
                   1520:  *
                   1521:  * Tk_MainLoop --
                   1522:  *
                   1523:  *     Call Tk_DoOneEvent over and over again in an infinite
                   1524:  *     loop as long as there exist any main windows.
                   1525:  *
                   1526:  * Results:
                   1527:  *     None.
                   1528:  *
                   1529:  * Side effects:
                   1530:  *     Arbitrary;  depends on handlers for events.
                   1531:  *
                   1532:  *--------------------------------------------------------------
                   1533:  */
                   1534: 
                   1535: void
                   1536: Tk_MainLoop()
                   1537: {
                   1538:     while (!tkMustExit &&
                   1539:           tk_NumMainWindows > 0) {
                   1540:        Tk_DoOneEvent(0);
                   1541:     }
                   1542: }
                   1543: 
                   1544: /*
                   1545:  *----------------------------------------------------------------------
                   1546:  *
                   1547:  * Tk_Sleep --
                   1548:  *
                   1549:  *     Delay execution for the specified number of milliseconds.
                   1550:  *
                   1551:  * Results:
                   1552:  *     None.
                   1553:  *
                   1554:  * Side effects:
                   1555:  *     Time passes.
                   1556:  *
                   1557:  *----------------------------------------------------------------------
                   1558:  */
                   1559: 
                   1560: void
                   1561: Tk_Sleep(ms)
                   1562:     int ms;                    /* Number of milliseconds to sleep. */
                   1563: {
                   1564:     static struct timeval delay;
                   1565: 
                   1566:     delay.tv_sec = ms/1000;
                   1567:     delay.tv_usec = (ms%1000)*1000;
                   1568:     (void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
                   1569:            (SELECT_MASK *) 0, &delay);
                   1570: }
                   1571: 
                   1572: /*
                   1573:  *----------------------------------------------------------------------
                   1574:  *
                   1575:  * Tk_RestrictEvents --
                   1576:  *
                   1577:  *     This procedure is used to globally restrict the set of events
                   1578:  *     that will be dispatched.  The restriction is done by filtering
                   1579:  *     all incoming X events through a procedure that determines
                   1580:  *     whether they are to be processed immediately or deferred.
                   1581:  *
                   1582:  * Results:
                   1583:  *     The return value is the previous restriction procedure in effect,
                   1584:  *     if there was one, or NULL if there wasn't.
                   1585:  *
                   1586:  * Side effects:
                   1587:  *     From now on, proc will be called to determine whether to process
                   1588:  *     or defer each incoming X event.
                   1589:  *
                   1590:  *----------------------------------------------------------------------
                   1591:  */
                   1592: 
                   1593: Tk_RestrictProc *
                   1594: Tk_RestrictEvents(proc, arg, prevArgPtr)
                   1595:     Tk_RestrictProc *proc;     /* X "if" procedure to call for each
                   1596:                                 * incoming event.  See "XIfEvent" doc.
                   1597:                                 * for details. */
                   1598:     char *arg;                 /* Arbitrary argument to pass to proc. */
                   1599:     char **prevArgPtr;         /* Place to store information about previous
                   1600:                                 * argument. */
                   1601: {
                   1602:     Bool (*prev)  _ANSI_ARGS_((Display *display, XEvent *eventPtr, char *arg));
                   1603: 
                   1604:     prev = restrictProc;
                   1605:     *prevArgPtr = restrictArg;
                   1606:     restrictProc = proc;
                   1607:     restrictArg = arg;
                   1608:     return prev;
                   1609: }
                   1610: 
                   1611: /*
                   1612:  *--------------------------------------------------------------
                   1613:  *
                   1614:  * Tk_CreateFocusHandler --
                   1615:  *
                   1616:  *     Arrange for a procedure to be called whenever the focus
                   1617:  *     enters or leaves a given window.
                   1618:  *
                   1619:  * Results:
                   1620:  *     None.
                   1621:  *
                   1622:  * Side effects:
                   1623:  *     After this procedure has been invoked, whenever tkwin gets
                   1624:  *     or loses the input focus, proc will be called.  It should have
                   1625:  *     the following structure:
                   1626:  *
                   1627:  *     void
                   1628:  *     proc(clientData, gotFocus)
                   1629:  *         ClientData clientData;
                   1630:  *         int gotFocus;
                   1631:  *     {
                   1632:  *     }
                   1633:  *
                   1634:  *     The clientData argument to "proc" will be the same as the
                   1635:  *     clientData argument to this procedure.  GotFocus will be
                   1636:  *     1 if tkwin is getting the focus, and 0 if it's losing the
                   1637:  *     focus.
                   1638:  *
                   1639:  *--------------------------------------------------------------
                   1640:  */
                   1641: 
                   1642: void
                   1643: Tk_CreateFocusHandler(tkwin, proc, clientData)
                   1644:     Tk_Window tkwin;           /* Token for window. */
                   1645:     Tk_FocusProc *proc;                /* Procedure to call when tkwin gets
                   1646:                                 * or loses the input focus. */
                   1647:     ClientData clientData;     /* Arbitrary value to pass to proc. */
                   1648: {
                   1649:     register TkWindow *winPtr = (TkWindow *) tkwin;
                   1650: 
                   1651:     winPtr->focusProc = proc;
                   1652:     winPtr->focusData = clientData;
                   1653: }
                   1654: 
                   1655: /*
                   1656:  *--------------------------------------------------------------
                   1657:  *
                   1658:  * Tk_FocusCmd --
                   1659:  *
                   1660:  *     This procedure is invoked to process the "focus" Tcl command.
                   1661:  *     See the user documentation for details on what it does.
                   1662:  *
                   1663:  * Results:
                   1664:  *     A standard Tcl result.
                   1665:  *
                   1666:  * Side effects:
                   1667:  *     See the user documentation.
                   1668:  *
                   1669:  *--------------------------------------------------------------
                   1670:  */
                   1671: 
                   1672: int
                   1673: Tk_FocusCmd(clientData, interp, argc, argv)
                   1674:     ClientData clientData;     /* Main window associated with
                   1675:                                 * interpreter. */
                   1676:     Tcl_Interp *interp;                /* Current interpreter. */
                   1677:     int argc;                  /* Number of arguments. */
                   1678:     char **argv;               /* Argument strings. */
                   1679: {
                   1680:     Tk_Window tkwin = (Tk_Window) clientData;
                   1681:     register TkWindow *winPtr = (TkWindow *) clientData;
                   1682:     register TkWindow *newPtr;
                   1683: 
                   1684:     if (argc > 3) {
                   1685:        focusSyntax:
                   1686:        Tcl_AppendResult(interp, "too many args: should be \"",
                   1687:                argv[0], " ?-query? ?window?\"", (char *) NULL);
                   1688:        return TCL_ERROR;
                   1689:     }
                   1690: 
                   1691:     if (argc == 1) {
                   1692:        if (winPtr->dispPtr->focusPtr == NULL) {
                   1693:            interp->result = "none";
                   1694:        } else {
                   1695:            interp->result = winPtr->dispPtr->focusPtr->pathName;
                   1696:        }
                   1697:        return TCL_OK;
                   1698:     }
                   1699: 
                   1700:     if (argv[1][0] == '-') {
                   1701:        int switchLength;
                   1702: 
                   1703:        switchLength = strlen(argv[1]);
                   1704:        if ((switchLength >= 2)
                   1705:                && (strncmp(argv[1], "-query", switchLength) == 0)) {
                   1706: 
                   1707:            if (argc != 3) {
                   1708:                goto focusSyntax;
                   1709:            }
                   1710: 
                   1711:            newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
                   1712:            if (newPtr == NULL) {
                   1713:                return TCL_ERROR;
                   1714:            }
                   1715:            if (newPtr->dispPtr->focusPtr == NULL) {
                   1716:                interp->result = "none";
                   1717:            } else {
                   1718:                interp->result = newPtr->dispPtr->focusPtr->pathName;
                   1719:            }
                   1720:            return TCL_OK;
                   1721:        }
                   1722:     }
                   1723: 
                   1724:     if (argc != 2) {
                   1725:        goto focusSyntax;
                   1726:     }
                   1727: 
                   1728:     if (strcmp(argv[1], "none") == 0) {
                   1729:        newPtr = NULL;
                   1730:     } else {
                   1731:        newPtr = (TkWindow *) Tk_NameToWindow(interp, argv[1], tkwin);
                   1732:        if (newPtr == NULL) {
                   1733:            return TCL_ERROR;
                   1734:        }
                   1735:     }
                   1736:     /* XXX: mumble frotz */
                   1737: /*    if (newPtr->dispPtr->focusPtr == newPtr) { */
                   1738:     if ((!newPtr) || (newPtr->dispPtr->focusPtr == newPtr)) {
                   1739:        return TCL_OK;
                   1740:     }
                   1741:     if (winPtr == newPtr->dispPtr->mouseMainPtr) { /* XXX: ??? presumably */
                   1742:        if ((newPtr->dispPtr->focusPtr != NULL)
                   1743:                && (newPtr->dispPtr->focusPtr->focusProc != NULL)) {
                   1744:            (*newPtr->dispPtr->focusPtr->focusProc)(
                   1745:                    newPtr->dispPtr->focusPtr->focusData, 0);
                   1746:        }
                   1747:        newPtr->dispPtr->focusPtr = newPtr;
                   1748:        if ((newPtr != NULL) && (newPtr->focusProc != NULL)) {
                   1749:            (*newPtr->focusProc)(newPtr->focusData, 1);
                   1750:        }
                   1751:     } else {
                   1752:        newPtr->dispPtr->focusPtr = newPtr;
                   1753:     }
                   1754:     return TCL_OK;
                   1755: }
                   1756: 
                   1757: /*
                   1758:  *--------------------------------------------------------------
                   1759:  *
                   1760:  * TkFocusEventProc --
                   1761:  *
                   1762:  *     This procedure is invoked whenever the pointer enters
                   1763:  *     or leaves a top-level window.  It notifies the current
                   1764:  *     owner of the focus, if any.
                   1765:  *
                   1766:  * Results:
                   1767:  *     None.
                   1768:  *
                   1769:  * Side effects:
                   1770:  *     None.
                   1771:  *
                   1772:  *--------------------------------------------------------------
                   1773:  */
                   1774: 
                   1775: void
                   1776: TkFocusEventProc(winPtr, eventPtr)
                   1777:     register TkWindow *winPtr; /* Top-level window just entered or left. */
                   1778:     XEvent *eventPtr;          /* EnterWindow or LeaveWindow event. */
                   1779: {
                   1780:     register TkWindow *focusPtr;
                   1781:     TkWindow *newMouseMainPtr = NULL;
                   1782: 
                   1783:     if (eventPtr->type == EnterNotify) {
                   1784:        newMouseMainPtr = winPtr->mainPtr->winPtr;
                   1785:     }
                   1786:     if (winPtr->dispPtr->mouseMainPtr == newMouseMainPtr) {
                   1787:        return;
                   1788:     }
                   1789:     if (winPtr->dispPtr->mouseMainPtr != NULL) {
                   1790:        focusPtr = winPtr->dispPtr->focusPtr;
                   1791:        if ((focusPtr != NULL)
                   1792:                && (focusPtr->focusProc != NULL)) {
                   1793:            (*focusPtr->focusProc)(focusPtr->focusData, 0);
                   1794:        }
                   1795:     }
                   1796:     winPtr->dispPtr->mouseMainPtr = newMouseMainPtr;
                   1797:     if (newMouseMainPtr != NULL) {
                   1798:        focusPtr = newMouseMainPtr->dispPtr->focusPtr;
                   1799:        if ((focusPtr != NULL)
                   1800:                && (focusPtr->focusProc != NULL)) {
                   1801:            (*focusPtr->focusProc)(focusPtr->focusData, 1);
                   1802:        }
                   1803:     }
                   1804: }
                   1805: 
                   1806: /*
                   1807:  *--------------------------------------------------------------
                   1808:  *
                   1809:  * TkEventDeadWindow --
                   1810:  *
                   1811:  *     This procedure is invoked when it is determined that
                   1812:  *     a window is dead.  It cleans up event-related information
                   1813:  *     about the window.
                   1814:  *
                   1815:  * Results:
                   1816:  *     None.
                   1817:  *
                   1818:  * Side effects:
                   1819:  *     Various things get cleaned up and recycled.
                   1820:  *
                   1821:  *--------------------------------------------------------------
                   1822:  */
                   1823: 
                   1824: void
                   1825: TkEventDeadWindow(winPtr)
                   1826:     TkWindow *winPtr;          /* Information about the window
                   1827:                                 * that is being deleted. */
                   1828: {
                   1829:     register TkEventHandler *handlerPtr;
                   1830:     register InProgress *ipPtr;
                   1831: 
                   1832:     /*
                   1833:      * While deleting all the handlers, be careful to check for
                   1834:      * Tk_HandleEvent being about to process one of the deleted
                   1835:      * handlers.  If it is, tell it to quit (all of the handlers
                   1836:      * are being deleted).
                   1837:      */
                   1838: 
                   1839:     while (winPtr->handlerList != NULL) {
                   1840:        handlerPtr = winPtr->handlerList;
                   1841:        winPtr->handlerList = handlerPtr->nextPtr;
                   1842:        for (ipPtr = pendingPtr; ipPtr != NULL; ipPtr = ipPtr->nextPtr) {
                   1843:            if (ipPtr->nextHandler == handlerPtr) {
                   1844:                ipPtr->nextHandler = NULL;
                   1845:            }
                   1846:            if (ipPtr->winPtr == winPtr) {
                   1847:                ipPtr->winPtr = None;
                   1848:            }
                   1849:        }
                   1850:        ckfree((char *) handlerPtr);
                   1851:     }
                   1852:     if ((winPtr->dispPtr != NULL) && (winPtr->dispPtr->focusPtr == winPtr)) {
                   1853:        winPtr->dispPtr->focusPtr = NULL;
                   1854:     }
                   1855: }
                   1856: 
                   1857: /*
                   1858:  *----------------------------------------------------------------------
                   1859:  *
                   1860:  * TkCurrentTime --
                   1861:  *
                   1862:  *     Try to deduce the current time.  "Current time" means the time
                   1863:  *     of the event that led to the current code being executed, which
                   1864:  *     means the time in the most recently-nested invocation of
                   1865:  *     Tk_HandleEvent.
                   1866:  *
                   1867:  * Results:
                   1868:  *     The return value is the time from the current event, or
                   1869:  *     CurrentTime if there is no current event or if the current
                   1870:  *     event contains no time.
                   1871:  *
                   1872:  * Side effects:
                   1873:  *     None.
                   1874:  *
                   1875:  *----------------------------------------------------------------------
                   1876:  */
                   1877: 
                   1878: Time
                   1879: TkCurrentTime(dispPtr)
                   1880:     TkDisplay *dispPtr;                /* Display for which the time is desired. */
                   1881: {
                   1882:     register XEvent *eventPtr;
                   1883: 
                   1884:     if (pendingPtr == NULL) {
                   1885:        return dispPtr->lastEventTime;
                   1886:     }
                   1887:     eventPtr = pendingPtr->eventPtr;
                   1888:     switch (eventPtr->type) {
                   1889:        case ButtonPress:
                   1890:        case ButtonRelease:
                   1891:            return eventPtr->xbutton.time;
                   1892:        case KeyPress:
                   1893:        case KeyRelease:
                   1894:            return eventPtr->xkey.time;
                   1895:        case MotionNotify:
                   1896:            return eventPtr->xmotion.time;
                   1897:        case EnterNotify:
                   1898:        case LeaveNotify:
                   1899:            return eventPtr->xcrossing.time;
                   1900:        case PropertyNotify:
                   1901:            return eventPtr->xproperty.time;
                   1902:     }
                   1903:     return dispPtr->lastEventTime;
                   1904: }

unix.superglobalmegacorp.com

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