Annotation of micropolis/src/tk/tkevent.c, revision 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.