4 * This file provides basic event-managing facilities, whereby
5 * procedure callbacks may be attached to certain events. It
6 * also contains the command procedures for the commands "after"
7 * and "fileevent", plus abridged versions of "tkwait" and
8 * "update", for use with Tk_EventInit.
10 * Copyright (c) 1990-1994 The Regents of the University of California.
11 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
13 * See the file "license.terms" for information on usage and redistribution
14 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
20 #if (TCL_MAJOR_VERSION == 7) && (TCL_MINOR_VERSION <= 4)
23 * For each timer callback that's pending, there is one record
24 * of the following type, chained together in a list sorted by
25 * time (earliest event first).
28 typedef struct TimerEvent {
29 struct timeval time; /* When timer is to fire. */
30 void (*proc) _ANSI_ARGS_((ClientData clientData));
31 /* Procedure to call. */
32 ClientData clientData; /* Argument to pass to proc. */
33 Tk_TimerToken token; /* Identifies event so it can be
35 struct TimerEvent *nextPtr; /* Next event in queue, or NULL for
39 static TimerEvent *firstTimerHandlerPtr;
40 /* First event in queue. */
43 * The information below is used to provide read, write, and
44 * exception masks to select during calls to Tk_DoOneEvent.
47 static fd_mask ready[3*MASK_SIZE];
48 /* Masks passed to select and modified
49 * by kernel to indicate which files are
51 static fd_mask check[3*MASK_SIZE];
52 /* Temporary set of masks, built up during
53 * Tk_DoOneEvent, that reflects what files
54 * we should wait for in the next select
55 * (doesn't include things that we've been
56 * asked to ignore in this call). */
57 static int numFds = 0; /* Number of valid bits in mask
58 * arrays (this value is passed
62 * For each file registered in a call to Tk_CreateFileHandler,
63 * and for each display that's currently active, there is one
64 * record of the following type. All of these records are
65 * chained together into a single list.
68 typedef struct FileHandler {
69 int fd; /* POSIX file descriptor for file. */
70 fd_mask *readPtr; /* Pointer to word in ready array
71 * for this file's read mask bit. */
72 fd_mask *writePtr; /* Same for write mask bit. */
73 fd_mask *exceptPtr; /* Same for except mask bit. */
74 fd_mask *checkReadPtr; /* Pointer to word in check array for
75 * this file's read mask bit. */
76 fd_mask *checkWritePtr; /* Same for write mask bit. */
77 fd_mask *checkExceptPtr; /* Same for except mask bit. */
78 fd_mask bitSelect; /* Value to AND with *readPtr etc. to
79 * select just this file's bit. */
80 int mask; /* Mask of desired events: TK_READABLE, etc. */
81 Tk_FileProc *proc; /* Procedure to call, in the style of
82 * Tk_CreateFileHandler. This is NULL
83 * if the handler was created by
84 * Tk_CreateFileHandler2. */
85 Tk_FileProc2 *proc2; /* Procedure to call, in the style of
86 * Tk_CreateFileHandler2. NULL means that
87 * the handler was created by
88 * Tk_CreateFileHandler. */
89 ClientData clientData; /* Argument to pass to proc. */
90 struct FileHandler *nextPtr;/* Next in list of all files we
91 * care about (NULL for end of
95 static FileHandler *firstFileHandlerPtr;
96 /* List of all file events. */
99 * There is one of the following structures for each of the
100 * handlers declared in a call to Tk_DoWhenIdle. All of the
101 * currently-active handlers are linked together into a list.
104 typedef struct IdleHandler {
105 void (*proc) _ANSI_ARGS_((ClientData clientData));
106 /* Procedure to call. */
107 ClientData clientData; /* Value to pass to proc. */
108 int generation; /* Used to distinguish older handlers from
109 * recently-created ones. */
110 struct IdleHandler *nextPtr;/* Next in list of active handlers. */
113 static IdleHandler *idleList = NULL;
114 /* First in list of all idle handlers. */
115 static IdleHandler *lastIdlePtr = NULL;
116 /* Last in list (or NULL for empty list). */
117 static int idleGeneration = 0; /* Used to fill in the "generation" fields
118 * of IdleHandler structures. Increments
119 * each time Tk_DoOneEvent starts calling
120 * idle handlers, so that all old handlers
121 * can be called without calling any of the
122 * new ones created by old ones. */
123 static int oldGeneration = 0; /* "generation" currently being handled. */
126 * The following procedure provides a secret hook for tkXEvent.c so that
127 * it can handle delayed mouse motion events at the right time.
130 void (*tkDelayedEventProc) _ANSI_ARGS_((void)) = NULL;
133 * One of the following structures exists for each file with a handler
134 * created by the "fileevent" command. Several of the fields are
135 * two-element arrays, in which the first element is used for read
136 * events and the second for write events.
139 typedef struct FileEvent {
140 FILE *f; /* Stdio handle for file. */
141 Tcl_Interp *interps[2]; /* Interpreters in which to execute
142 * scripts. NULL means no handler
144 char *scripts[2]; /* Scripts to evaluate in response to
145 * events (malloc'ed). NULL means no
146 * handler for event. */
147 struct FileEvent *nextPtr; /* Next in list of all file events
148 * currently defined. */
151 static FileEvent *firstFileEventPtr = NULL;
152 /* First in list of all existing
156 * The data structure below is used by the "after" command to remember
157 * the command to be executed later.
160 typedef struct AfterInfo {
161 Tcl_Interp *interp; /* Interpreter in which to execute command. */
162 char *command; /* Command to execute. Malloc'ed, so must
163 * be freed when structure is deallocated. */
164 int id; /* Integer identifier for command; used to
166 Tk_TimerToken token; /* Used to cancel the "after" command. NULL
167 * means that the command is run as an
168 * idle handler rather than as a timer
170 struct AfterInfo *nextPtr; /* Next in list of all "after" commands for
171 * the application. */
174 static AfterInfo *firstAfterPtr = NULL;
175 /* First in list of all pending "after"
179 * The data structure below is used to report background errors. One
180 * such structure is allocated for each error; it holds information
181 * about the interpreter and the error until tkerror can be invoked
182 * later as an idle handler.
185 typedef struct BgError {
186 Tcl_Interp *interp; /* Interpreter in which error occurred. NULL
187 * means this error report has been cancelled
188 * (a previous report generated a break). */
189 char *errorMsg; /* The error message (interp->result when
190 * the error occurred). Malloc-ed. */
191 char *errorInfo; /* Value of the errorInfo variable
193 char *errorCode; /* Value of the errorCode variable
195 struct BgError *nextPtr; /* Next in list of all pending error
199 static BgError *firstBgPtr = NULL;
200 /* First in list of all background errors
201 * waiting to be processed (NULL if none). */
202 static BgError *lastBgPtr = NULL;
203 /* First in list of all background errors
204 * waiting to be processed (NULL if none). */
207 * Prototypes for procedures referenced only in this file:
210 static void AfterProc _ANSI_ARGS_((ClientData clientData));
211 static void DeleteFileEvent _ANSI_ARGS_((FILE *f));
212 static int FileEventProc _ANSI_ARGS_((ClientData clientData,
213 int mask, int flags));
214 static void FreeAfterPtr _ANSI_ARGS_((AfterInfo *afterPtr));
215 static void HandleBgErrors _ANSI_ARGS_((ClientData clientData));
216 static int TkwaitCmd2 _ANSI_ARGS_((ClientData clientData,
217 Tcl_Interp *interp, int argc, char **argv));
218 static int UpdateCmd2 _ANSI_ARGS_((ClientData clientData,
219 Tcl_Interp *interp, int argc, char **argv));
220 static char * WaitVariableProc2 _ANSI_ARGS_((ClientData clientData,
221 Tcl_Interp *interp, char *name1, char *name2,
225 *--------------------------------------------------------------
227 * Tk_CreateFileHandler --
229 * Arrange for a given procedure to be invoked whenever
230 * a given file becomes readable or writable.
236 * From now on, whenever the I/O channel given by fd becomes
237 * ready in the way indicated by mask, proc will be invoked.
238 * See the manual entry for details on the calling sequence
239 * to proc. If fd is already registered then the old mask
240 * and proc and clientData values will be replaced with
243 *--------------------------------------------------------------
247 Tk_CreateFileHandler(fd, mask, proc, clientData)
248 int fd; /* Integer identifier for stream. */
249 int mask; /* OR'ed combination of TK_READABLE,
250 * TK_WRITABLE, and TK_EXCEPTION:
251 * indicates conditions under which
252 * proc should be called. TK_IS_DISPLAY
253 * indicates that this is a display and that
254 * clientData is the (Display *) for it,
255 * and that events should be handled
257 Tk_FileProc *proc; /* Procedure to call for each
259 ClientData clientData; /* Arbitrary data to pass to proc. */
261 register FileHandler *filePtr;
264 if (fd >= FD_SETSIZE) {
265 panic("Tk_CreatefileHandler can't handle file id %d", fd);
269 * Make sure the file isn't already registered. Create a
270 * new record in the normal case where there's no existing
274 for (filePtr = firstFileHandlerPtr; filePtr != NULL;
275 filePtr = filePtr->nextPtr) {
276 if (filePtr->fd == fd) {
280 index = fd/(NBBY*sizeof(fd_mask));
281 if (filePtr == NULL) {
282 filePtr = (FileHandler *) ckalloc(sizeof(FileHandler));
284 filePtr->readPtr = &ready[index];
285 filePtr->writePtr = &ready[index+MASK_SIZE];
286 filePtr->exceptPtr = &ready[index+2*MASK_SIZE];
287 filePtr->checkReadPtr = &check[index];
288 filePtr->checkWritePtr = &check[index+MASK_SIZE];
289 filePtr->checkExceptPtr = &check[index+2*MASK_SIZE];
290 filePtr->bitSelect = 1 << (fd%(NBBY*sizeof(fd_mask)));
291 filePtr->nextPtr = firstFileHandlerPtr;
292 firstFileHandlerPtr = filePtr;
296 * The remainder of the initialization below is done
297 * regardless of whether or not this is a new record
298 * or a modification of an old one.
301 filePtr->mask = mask;
302 filePtr->proc = proc;
303 filePtr->proc2 = NULL;
304 filePtr->clientData = clientData;
312 *--------------------------------------------------------------
314 * Tk_CreateFileHandler2 --
316 * Arrange for a given procedure to be invoked during the
317 * event loop to handle a particular file.
323 * In each pass through Tk_DoOneEvent, proc will be invoked to
324 * decide whether fd is "ready" and take appropriate action if
325 * it is. See the manual entry for details on the calling
326 * sequence to proc. If a handler for fd has already been
327 * registered then it is superseded by the new one.
329 *--------------------------------------------------------------
333 Tk_CreateFileHandler2(fd, proc, clientData)
334 int fd; /* Integer identifier for stream. */
335 Tk_FileProc2 *proc; /* Procedure to call from the event
337 ClientData clientData; /* Arbitrary data to pass to proc. */
339 register FileHandler *filePtr;
342 * Let Tk_CreateFileHandler do all of the work of setting up
343 * the handler, then just modify things a bit after it returns.
346 Tk_CreateFileHandler(fd, 0, (Tk_FileProc *) NULL, clientData);
347 for (filePtr = firstFileHandlerPtr; filePtr->fd != fd;
348 filePtr = filePtr->nextPtr) {
349 /* Empty loop body. */
351 filePtr->proc = NULL;
352 filePtr->proc2 = proc;
356 *--------------------------------------------------------------
358 * Tk_DeleteFileHandler --
360 * Cancel a previously-arranged callback arrangement for
367 * If a callback was previously registered on fd, remove it.
369 *--------------------------------------------------------------
373 Tk_DeleteFileHandler(fd)
374 int fd; /* Stream id for which to remove
375 * callback procedure. */
377 register FileHandler *filePtr;
378 FileHandler *prevPtr;
381 * Find the entry for the given file (and return if there
385 for (prevPtr = NULL, filePtr = firstFileHandlerPtr; ;
386 prevPtr = filePtr, filePtr = filePtr->nextPtr) {
387 if (filePtr == NULL) {
390 if (filePtr->fd == fd) {
396 * Clean up information in the callback record.
399 if (prevPtr == NULL) {
400 firstFileHandlerPtr = filePtr->nextPtr;
402 prevPtr->nextPtr = filePtr->nextPtr;
404 ckfree((char *) filePtr);
411 for (filePtr = firstFileHandlerPtr; filePtr != NULL;
412 filePtr = filePtr->nextPtr) {
413 if (numFds <= filePtr->fd) {
414 numFds = filePtr->fd+1;
420 *--------------------------------------------------------------
422 * Tk_CreateTimerHandler --
424 * Arrange for a given procedure to be invoked at a particular
425 * time in the future.
428 * The return value is a token for the timer event, which
429 * may be used to delete the event before it fires.
432 * When milliseconds have elapsed, proc will be invoked
435 *--------------------------------------------------------------
439 Tk_CreateTimerHandler(milliseconds, proc, clientData)
440 int milliseconds; /* How many milliseconds to wait
441 * before invoking proc. */
442 Tk_TimerProc *proc; /* Procedure to invoke. */
443 ClientData clientData; /* Arbitrary data to pass to proc. */
445 register TimerEvent *timerPtr, *tPtr2, *prevPtr;
448 timerPtr = (TimerEvent *) ckalloc(sizeof(TimerEvent));
451 * Compute when the event should fire.
454 (void) gettimeofday(&timerPtr->time, (struct timezone *) NULL);
455 timerPtr->time.tv_sec += milliseconds/1000;
456 timerPtr->time.tv_usec += (milliseconds%1000)*1000;
457 if (timerPtr->time.tv_usec >= 1000000) {
458 timerPtr->time.tv_usec -= 1000000;
459 timerPtr->time.tv_sec += 1;
463 * Fill in other fields for the event.
466 timerPtr->proc = proc;
467 timerPtr->clientData = clientData;
469 timerPtr->token = (Tk_TimerToken) id;
472 * Add the event to the queue in the correct position
473 * (ordered by event firing time).
476 for (tPtr2 = firstTimerHandlerPtr, prevPtr = NULL; tPtr2 != NULL;
477 prevPtr = tPtr2, tPtr2 = tPtr2->nextPtr) {
478 if ((tPtr2->time.tv_sec > timerPtr->time.tv_sec)
479 || ((tPtr2->time.tv_sec == timerPtr->time.tv_sec)
480 && (tPtr2->time.tv_usec > timerPtr->time.tv_usec))) {
484 if (prevPtr == NULL) {
485 timerPtr->nextPtr = firstTimerHandlerPtr;
486 firstTimerHandlerPtr = timerPtr;
488 timerPtr->nextPtr = prevPtr->nextPtr;
489 prevPtr->nextPtr = timerPtr;
491 return timerPtr->token;
495 *--------------------------------------------------------------
497 * Tk_DeleteTimerHandler --
499 * Delete a previously-registered timer handler.
505 * Destroy the timer callback identified by TimerToken,
506 * so that its associated procedure will not be called.
507 * If the callback has already fired, or if the given
508 * token doesn't exist, then nothing happens.
510 *--------------------------------------------------------------
514 Tk_DeleteTimerHandler(token)
515 Tk_TimerToken token; /* Result previously returned by
516 * Tk_DeleteTimerHandler. */
518 register TimerEvent *timerPtr, *prevPtr;
520 for (timerPtr = firstTimerHandlerPtr, prevPtr = NULL; timerPtr != NULL;
521 prevPtr = timerPtr, timerPtr = timerPtr->nextPtr) {
522 if (timerPtr->token != token) {
525 if (prevPtr == NULL) {
526 firstTimerHandlerPtr = timerPtr->nextPtr;
528 prevPtr->nextPtr = timerPtr->nextPtr;
530 ckfree((char *) timerPtr);
536 *--------------------------------------------------------------
540 * Arrange for proc to be invoked the next time the
541 * system is idle (i.e., just before the next time
542 * that Tk_DoOneEvent would have to wait for something
549 * Proc will eventually be called, with clientData
550 * as argument. See the manual entry for details.
552 *--------------------------------------------------------------
556 Tk_DoWhenIdle(proc, clientData)
557 Tk_IdleProc *proc; /* Procedure to invoke. */
558 ClientData clientData; /* Arbitrary value to pass to proc. */
560 register IdleHandler *idlePtr;
562 idlePtr = (IdleHandler *) ckalloc(sizeof(IdleHandler));
563 idlePtr->proc = proc;
564 idlePtr->clientData = clientData;
565 idlePtr->generation = idleGeneration;
566 idlePtr->nextPtr = NULL;
567 if (lastIdlePtr == NULL) {
570 lastIdlePtr->nextPtr = idlePtr;
572 lastIdlePtr = idlePtr;
576 *--------------------------------------------------------------
580 * Arrange for proc to be invoked when the system is idle
581 * (i.e., if currently idle or just before the next time
582 * that Tk_DoOneEvent would have to wait for something
589 * Proc will eventually be called, with clientData
590 * as argument. See the manual entry for details.
592 *--------------------------------------------------------------
596 Tk_DoWhenIdle2(proc, clientData)
597 Tk_IdleProc *proc; /* Procedure to invoke. */
598 ClientData clientData; /* Arbitrary value to pass to proc. */
600 register IdleHandler *idlePtr;
602 idlePtr = (IdleHandler *) ckalloc(sizeof(IdleHandler));
603 idlePtr->proc = proc;
604 idlePtr->clientData = clientData;
605 idlePtr->generation = idleList == NULL ? oldGeneration :
606 idleList->generation;
607 idlePtr->nextPtr = NULL;
608 if (lastIdlePtr == NULL) {
611 lastIdlePtr->nextPtr = idlePtr;
613 lastIdlePtr = idlePtr;
617 *----------------------------------------------------------------------
619 * Tk_CancelIdleCall --
621 * If there are any when-idle calls requested to a given procedure
622 * with given clientData, cancel all of them.
628 * If the proc/clientData combination were on the when-idle list,
629 * they are removed so that they will never be called.
631 *----------------------------------------------------------------------
635 Tk_CancelIdleCall(proc, clientData)
636 Tk_IdleProc *proc; /* Procedure that was previously registered. */
637 ClientData clientData; /* Arbitrary value to pass to proc. */
639 register IdleHandler *idlePtr, *prevPtr;
640 IdleHandler *nextPtr;
642 for (prevPtr = NULL, idlePtr = idleList; idlePtr != NULL;
643 prevPtr = idlePtr, idlePtr = idlePtr->nextPtr) {
644 while ((idlePtr->proc == proc)
645 && (idlePtr->clientData == clientData)) {
646 nextPtr = idlePtr->nextPtr;
647 ckfree((char *) idlePtr);
649 if (prevPtr == NULL) {
652 prevPtr->nextPtr = idlePtr;
654 if (idlePtr == NULL) {
655 lastIdlePtr = prevPtr;
663 *--------------------------------------------------------------
667 * Process a single event of some sort. If there's no
668 * work to do, wait for an event to occur, then process
672 * The return value is 1 if the procedure actually found
673 * an event to process. If no event was found then 0 is
677 * May delay execution of process while waiting for an
678 * X event, X error, file-ready event, or timer event.
679 * The handling of the event could cause additional
680 * side effects. Collapses sequences of mouse-motion
681 * events for the same window into a single event by
682 * delaying motion event processing.
684 *--------------------------------------------------------------
689 int flags; /* Miscellaneous flag values: may be any
690 * combination of TK_DONT_WAIT, TK_X_EVENTS,
691 * TK_FILE_EVENTS, TK_TIMER_EVENTS, and
694 register FileHandler *filePtr;
695 struct timeval curTime, timeoutVal, *timeoutPtr;
696 int numFound, mask, anyFilesToWaitFor;
698 if ((flags & TK_ALL_EVENTS) == 0) {
699 flags |= TK_ALL_EVENTS;
703 * Phase One: see if there's a ready file that was left over
704 * from before (i.e don't do a select, just check the bits from
709 if (tcl_AsyncReady) {
710 (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
713 memset((VOID *) check, 0, 3*MASK_SIZE*sizeof(fd_mask));
714 anyFilesToWaitFor = 0;
715 for (filePtr = firstFileHandlerPtr; filePtr != NULL;
716 filePtr = filePtr->nextPtr) {
718 if (*filePtr->readPtr & filePtr->bitSelect) {
720 *filePtr->readPtr &= ~filePtr->bitSelect;
722 if (*filePtr->writePtr & filePtr->bitSelect) {
724 *filePtr->writePtr &= ~filePtr->bitSelect;
726 if (*filePtr->exceptPtr & filePtr->bitSelect) {
727 mask |= TK_EXCEPTION;
728 *filePtr->exceptPtr &= ~filePtr->bitSelect;
730 if (filePtr->proc2 != NULL) {
732 * Handler created by Tk_CreateFileHandler2.
735 mask = (*filePtr->proc2)(filePtr->clientData, mask, flags);
736 if (mask == TK_FILE_HANDLED) {
741 * Handler created by Tk_CreateFileHandler.
744 if (!(flags & TK_FILE_EVENTS)) {
748 (*filePtr->proc)(filePtr->clientData, mask);
751 mask = filePtr->mask;
754 anyFilesToWaitFor = 1;
755 if (mask & TK_READABLE) {
756 *filePtr->checkReadPtr |= filePtr->bitSelect;
758 if (mask & TK_WRITABLE) {
759 *filePtr->checkWritePtr |= filePtr->bitSelect;
761 if (mask & TK_EXCEPTION) {
762 *filePtr->checkExceptPtr |= filePtr->bitSelect;
768 * Phase Two: get the current time and see if any timer
769 * events are ready to fire. If so, fire one and return.
773 if ((firstTimerHandlerPtr != NULL) && (flags & TK_TIMER_EVENTS)) {
774 register TimerEvent *timerPtr = firstTimerHandlerPtr;
776 (void) gettimeofday(&curTime, (struct timezone *) NULL);
777 if ((timerPtr->time.tv_sec < curTime.tv_sec)
778 || ((timerPtr->time.tv_sec == curTime.tv_sec)
779 && (timerPtr->time.tv_usec < curTime.tv_usec))) {
780 firstTimerHandlerPtr = timerPtr->nextPtr;
781 (*timerPtr->proc)(timerPtr->clientData);
782 ckfree((char *) timerPtr);
788 * Phase Three: if there are DoWhenIdle requests pending (or
789 * if we're not allowed to block), then do a select with an
790 * instantaneous timeout. If a ready file is found, then go
791 * back to process it.
794 if (((idleList != NULL) && (flags & TK_IDLE_EVENTS))
795 || (flags & TK_DONT_WAIT)) {
796 if (flags & (TK_X_EVENTS|TK_FILE_EVENTS)) {
797 memcpy((VOID *) ready, (VOID *) check,
798 3*MASK_SIZE*sizeof(fd_mask));
799 timeoutVal.tv_sec = timeoutVal.tv_usec = 0;
800 numFound = select(numFds, (SELECT_MASK *) &ready[0],
801 (SELECT_MASK *) &ready[MASK_SIZE],
802 (SELECT_MASK *) &ready[2*MASK_SIZE], &timeoutVal);
805 * Some systems don't clear the masks after an error, so
806 * we have to do it here.
809 memset((VOID *) ready, 0, 3*MASK_SIZE*sizeof(fd_mask));
811 if ((numFound > 0) || ((numFound == -1) && (errno == EINTR))) {
818 * Phase Four: if there is a delayed motion event then call a procedure
819 * to handle it. Do it now, before calling any DoWhenIdle handlers,
820 * since the goal of idle handlers is to delay until after all pending
821 * events have been processed.
823 * The particular implementation of this (a procedure variable shared
824 * with tkXEvent.c) is a bit kludgy, but it allows this file to be used
825 * separately without any of the rest of Tk.
828 if ((tkDelayedEventProc != NULL) && (flags & TK_X_EVENTS)) {
829 (*tkDelayedEventProc)();
834 * Phase Five: process all pending DoWhenIdle requests.
837 if ((idleList != NULL) && (flags & TK_IDLE_EVENTS)) {
838 register IdleHandler *idlePtr;
841 oldGeneration = myGeneration = idleList->generation;
845 * The code below is trickier than it may look, for the following
848 * 1. New handlers can get added to the list while the current
849 * one is being processed. If new ones get added, we don't
850 * want to process them during this pass through the list (want
851 * to check for other work to do first). This is implemented
852 * using the generation number in the handler: new handlers
853 * will have a different generation than any of the ones currently
855 * 2. The handler can call Tk_DoOneEvent, so we have to remove
856 * the hander from the list before calling it. Otherwise an
857 * infinite loop could result.
858 * 3. Tk_CancelIdleCall can be called to remove an element from
859 * the list while a handler is executing, so the list could
860 * change structure during the call.
863 for (idlePtr = idleList;
864 ((idlePtr != NULL) && (idlePtr->generation == myGeneration));
865 idlePtr = idleList) {
866 idleList = idlePtr->nextPtr;
867 if (idleList == NULL) {
870 (*idlePtr->proc)(idlePtr->clientData);
871 ckfree((char *) idlePtr);
877 * Phase Six: do a select to wait for either one of the
878 * files to become ready or for the first timer event to
879 * fire. Then go back to process the event.
882 if ((flags & TK_DONT_WAIT)
883 || !(flags & (TK_TIMER_EVENTS|TK_FILE_EVENTS|TK_X_EVENTS))) {
886 if ((firstTimerHandlerPtr == NULL) || !(flags & TK_TIMER_EVENTS)) {
889 timeoutPtr = &timeoutVal;
890 timeoutVal.tv_sec = firstTimerHandlerPtr->time.tv_sec
892 timeoutVal.tv_usec = firstTimerHandlerPtr->time.tv_usec
894 if (timeoutVal.tv_usec < 0) {
895 timeoutVal.tv_sec -= 1;
896 timeoutVal.tv_usec += 1000000;
899 if ((timeoutPtr == NULL) && !anyFilesToWaitFor) {
902 memcpy((VOID *) ready, (VOID *) check, 3*MASK_SIZE*sizeof(fd_mask));
903 numFound = select(numFds, (SELECT_MASK *) &ready[0],
904 (SELECT_MASK *) &ready[MASK_SIZE],
905 (SELECT_MASK *) &ready[2*MASK_SIZE], timeoutPtr);
906 if (numFound == -1) {
908 * Some systems don't clear the masks after an error, so
909 * we have to do it here.
912 memset((VOID *) ready, 0, 3*MASK_SIZE*sizeof(fd_mask));
921 *----------------------------------------------------------------------
925 * Delay execution for the specified number of milliseconds.
933 *----------------------------------------------------------------------
938 int ms; /* Number of milliseconds to sleep. */
940 static struct timeval delay;
942 delay.tv_sec = ms/1000;
943 delay.tv_usec = (ms%1000)*1000;
944 (void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
945 (SELECT_MASK *) 0, &delay);
949 *----------------------------------------------------------------------
951 * Tk_BackgroundError --
953 * This procedure is invoked to handle errors that occur in Tcl
954 * commands that are invoked in "background" (e.g. from event or
961 * The command "tkerror" is invoked later as an idle handler to
962 * process the error, passing it the error message. If that fails,
963 * then an error message is output on stderr.
965 *----------------------------------------------------------------------
969 Tk_BackgroundError(interp)
970 Tcl_Interp *interp; /* Interpreter in which an error has
977 * The Tcl_AddErrorInfo call below (with an empty string) ensures that
978 * errorInfo gets properly set. It's needed in cases where the error
979 * came from a utility procedure like Tcl_GetVar instead of Tcl_Eval;
980 * in these cases errorInfo still won't have been set when this
981 * procedure is called.
984 Tcl_AddErrorInfo(interp, "");
985 errPtr = (BgError *) ckalloc(sizeof(BgError));
986 errPtr->interp = interp;
987 errPtr->errorMsg = (char *) ckalloc((unsigned) (strlen(interp->result)
989 strcpy(errPtr->errorMsg, interp->result);
990 varValue = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
991 if (varValue == NULL) {
992 varValue = errPtr->errorMsg;
994 errPtr->errorInfo = (char *) ckalloc((unsigned) (strlen(varValue) + 1));
995 strcpy(errPtr->errorInfo, varValue);
996 varValue = Tcl_GetVar(interp, "errorCode", TCL_GLOBAL_ONLY);
997 if (varValue == NULL) {
1000 errPtr->errorCode = (char *) ckalloc((unsigned) (strlen(varValue) + 1));
1001 strcpy(errPtr->errorCode, varValue);
1002 errPtr->nextPtr = NULL;
1003 if (firstBgPtr == NULL) {
1004 firstBgPtr = errPtr;
1005 Tk_DoWhenIdle(HandleBgErrors, (ClientData) NULL);
1007 lastBgPtr->nextPtr = errPtr;
1010 Tcl_ResetResult(interp);
1014 *----------------------------------------------------------------------
1018 * This procedure is invoked as an idle handler to process all of
1019 * the accumulated background errors.
1025 * Depends on what actions "tkerror" takes for the errors.
1027 *----------------------------------------------------------------------
1031 HandleBgErrors(clientData)
1032 ClientData clientData; /* Not used. */
1040 while (firstBgPtr != NULL) {
1041 interp = firstBgPtr->interp;
1042 if (interp == NULL) {
1043 goto doneWithReport;
1047 * Restore important state variables to what they were at
1048 * the time the error occurred.
1051 Tcl_SetVar(interp, "errorInfo", firstBgPtr->errorInfo,
1053 Tcl_SetVar(interp, "errorCode", firstBgPtr->errorCode,
1057 * Create and invoke the tkerror command.
1060 argv[0] = "tkerror";
1061 argv[1] = firstBgPtr->errorMsg;
1062 command = Tcl_Merge(2, argv);
1063 Tcl_AllowExceptions(interp);
1064 code = Tcl_GlobalEval(interp, command);
1066 if (code == TCL_ERROR) {
1067 if (strcmp(interp->result, "\"tkerror\" is an invalid command name or ambiguous abbreviation") == 0) {
1068 fprintf(stderr, "%s\n", firstBgPtr->errorInfo);
1070 fprintf(stderr, "tkerror failed to handle background error.\n");
1071 fprintf(stderr, " Original error: %s\n",
1072 firstBgPtr->errorMsg);
1073 fprintf(stderr, " Error in tkerror: %s\n", interp->result);
1075 } else if (code == TCL_BREAK) {
1077 * Break means cancel any remaining error reports for this
1081 for (errPtr = firstBgPtr; errPtr != NULL;
1082 errPtr = errPtr->nextPtr) {
1083 if (errPtr->interp == interp) {
1084 errPtr->interp = NULL;
1090 * Discard the command and the information about the error report.
1094 ckfree(firstBgPtr->errorMsg);
1095 ckfree(firstBgPtr->errorInfo);
1096 ckfree(firstBgPtr->errorCode);
1097 errPtr = firstBgPtr->nextPtr;
1098 ckfree((char *) firstBgPtr);
1099 firstBgPtr = errPtr;
1105 *----------------------------------------------------------------------
1109 * This procedure is invoked to process the "after" Tcl command.
1110 * See the user documentation for details on what it does.
1113 * A standard Tcl result.
1116 * See the user documentation.
1118 *----------------------------------------------------------------------
1123 Tk_AfterCmd(clientData, interp, argc, argv)
1124 ClientData clientData; /* Main window associated with
1125 * interpreter. Not used.*/
1126 Tcl_Interp *interp; /* Current interpreter. */
1127 int argc; /* Number of arguments. */
1128 char **argv; /* Argument strings. */
1131 * The variable below is used to generate unique identifiers for
1132 * after commands. This id can wrap around, which can potentially
1133 * cause problems. However, there are not likely to be problems
1134 * in practice, because after commands can only be requested to
1135 * about a month in the future, and wrap-around is unlikely to
1136 * occur in less than about 1-10 years. Thus it's unlikely that
1137 * any old ids will still be around when wrap-around occurs.
1140 static int nextId = 1;
1142 AfterInfo *afterPtr;
1145 Tcl_AppendResult(interp, "wrong # args: should be \"",
1146 argv[0], " milliseconds ?command? ?arg arg ...?\" or \"",
1147 argv[0], " cancel id|command\"", (char *) NULL);
1151 if (isdigit((unsigned char) argv[1][0])) {
1152 if (Tcl_GetInt(interp, argv[1], &ms) != TCL_OK) {
1162 afterPtr = (AfterInfo *) ckalloc((unsigned) (sizeof(AfterInfo)));
1163 afterPtr->interp = interp;
1165 afterPtr->command = (char *) ckalloc((unsigned)
1166 (strlen(argv[2]) + 1));
1167 strcpy(afterPtr->command, argv[2]);
1169 afterPtr->command = Tcl_Concat(argc-2, argv+2);
1171 afterPtr->id = nextId;
1173 afterPtr->token = Tk_CreateTimerHandler(ms, AfterProc,
1174 (ClientData) afterPtr);
1175 afterPtr->nextPtr = firstAfterPtr;
1176 firstAfterPtr = afterPtr;
1177 sprintf(interp->result, "after#%d", afterPtr->id);
1178 } else if (strncmp(argv[1], "cancel", strlen(argv[1])) == 0) {
1182 Tcl_AppendResult(interp, "wrong # args: should be \"",
1183 argv[0], " cancel id|command\"", (char *) NULL);
1189 arg = Tcl_Concat(argc-2, argv+2);
1191 if (strncmp(arg, "after#", 6) == 0) {
1192 if (Tcl_GetInt(interp, arg+6, &id) != TCL_OK) {
1195 for (afterPtr = firstAfterPtr; afterPtr != NULL;
1196 afterPtr = afterPtr->nextPtr) {
1197 if (afterPtr->id == id) {
1202 for (afterPtr = firstAfterPtr; afterPtr != NULL;
1203 afterPtr = afterPtr->nextPtr) {
1204 if (strcmp(afterPtr->command, arg) == 0) {
1209 if (arg != argv[2]) {
1212 if (afterPtr != NULL) {
1213 if (afterPtr->token != NULL) {
1214 Tk_DeleteTimerHandler(afterPtr->token);
1216 Tk_CancelIdleCall(AfterProc, (ClientData) afterPtr);
1218 FreeAfterPtr(afterPtr);
1220 } else if (strncmp(argv[1], "idle", strlen(argv[1])) == 0) {
1222 Tcl_AppendResult(interp, "wrong # args: should be \"",
1223 argv[0], " idle script script ...\"", (char *) NULL);
1226 afterPtr = (AfterInfo *) ckalloc((unsigned) (sizeof(AfterInfo)));
1227 afterPtr->interp = interp;
1229 afterPtr->command = (char *) ckalloc((unsigned)
1230 (strlen(argv[2]) + 1));
1231 strcpy(afterPtr->command, argv[2]);
1233 afterPtr->command = Tcl_Concat(argc-2, argv+2);
1235 afterPtr->id = nextId;
1237 afterPtr->token = NULL;
1238 afterPtr->nextPtr = firstAfterPtr;
1239 firstAfterPtr = afterPtr;
1240 Tk_DoWhenIdle(AfterProc, (ClientData) afterPtr);
1241 sprintf(interp->result, "after#%d", afterPtr->id);
1243 Tcl_AppendResult(interp, "bad argument \"", argv[1],
1244 "\": must be cancel, idle, or a number", (char *) NULL);
1251 *----------------------------------------------------------------------
1255 * Timer callback to execute commands registered with the
1262 * Executes whatever command was specified. If the command
1263 * returns an error, then the command "tkerror" is invoked
1264 * to process the error; if tkerror fails then information
1265 * about the error is output on stderr.
1267 *----------------------------------------------------------------------
1271 AfterProc(clientData)
1272 ClientData clientData; /* Describes command to execute. */
1274 AfterInfo *afterPtr = (AfterInfo *) clientData;
1279 * First remove the callback from our list of callbacks; otherwise
1280 * someone could delete the callback while it's being executed, which
1281 * could cause a core dump.
1284 if (firstAfterPtr == afterPtr) {
1285 firstAfterPtr = afterPtr->nextPtr;
1287 for (prevPtr = firstAfterPtr; prevPtr->nextPtr != afterPtr;
1288 prevPtr = prevPtr->nextPtr) {
1289 /* Empty loop body. */
1291 prevPtr->nextPtr = afterPtr->nextPtr;
1295 * Execute the callback.
1298 result = Tcl_GlobalEval(afterPtr->interp, afterPtr->command);
1299 if (result != TCL_OK) {
1300 Tcl_AddErrorInfo(afterPtr->interp, "\n (\"after\" script)");
1301 Tk_BackgroundError(afterPtr->interp);
1305 * Free the memory for the callback.
1308 ckfree(afterPtr->command);
1309 ckfree((char *) afterPtr);
1313 *----------------------------------------------------------------------
1317 * This procedure removes an "after" command from the list of
1318 * those that are pending and frees its resources. This procedure
1319 * does *not* cancel the timer handler; if that's needed, the
1320 * caller must do it.
1326 * The memory associated with afterPtr is released.
1328 *----------------------------------------------------------------------
1332 FreeAfterPtr(afterPtr)
1333 AfterInfo *afterPtr; /* Command to be deleted. */
1336 if (firstAfterPtr == afterPtr) {
1337 firstAfterPtr = afterPtr->nextPtr;
1339 for (prevPtr = firstAfterPtr; prevPtr->nextPtr != afterPtr;
1340 prevPtr = prevPtr->nextPtr) {
1341 /* Empty loop body. */
1343 prevPtr->nextPtr = afterPtr->nextPtr;
1345 ckfree(afterPtr->command);
1346 ckfree((char *) afterPtr);
1350 *----------------------------------------------------------------------
1352 * Tk_FileeventCmd --
1354 * This procedure is invoked to process the "fileevent" Tcl
1355 * command. See the user documentation for details on what it does.
1356 * This command is based on Mark Diekhans' "addinput" command.
1359 * A standard Tcl result.
1362 * See the user documentation.
1364 *----------------------------------------------------------------------
1369 Tk_FileeventCmd(clientData, interp, argc, argv)
1370 ClientData clientData; /* Main window associated with interpreter.
1372 Tcl_Interp *interp; /* Current interpreter. */
1373 int argc; /* Number of arguments. */
1374 char **argv; /* Argument strings. */
1379 FileEvent *fevPtr, *prevPtr;
1385 if ((argc != 3) && (argc != 4)) {
1386 Tcl_AppendResult(interp, "wrong # args: must be \"", argv[0],
1387 " fileId event ?script?", (char *) NULL);
1391 length = strlen(argv[2]);
1392 if ((c == 'r') && (strncmp(argv[2], "readable", length) == 0)) {
1394 } else if ((c == 'w') && (strncmp(argv[2], "writable", length) == 0)) {
1397 Tcl_AppendResult(interp, "bad event name \"", argv[2],
1398 "\": must be readable or writable", (char *) NULL);
1401 if (Tcl_GetOpenFile(interp, argv[1], index, 1, &f) != TCL_OK) {
1407 * Locate an existing file handler for this file, if one exists,
1408 * and make a new one if none currently exists.
1411 for (fevPtr = firstFileEventPtr; ; fevPtr = fevPtr->nextPtr) {
1412 if (fevPtr == NULL) {
1413 if ((argc == 3) || (argv[3][0] == 0)) {
1416 fevPtr = (FileEvent *) ckalloc(sizeof(FileEvent));
1418 fevPtr->interps[0] = NULL;
1419 fevPtr->interps[1] = NULL;
1420 fevPtr->scripts[0] = NULL;
1421 fevPtr->scripts[1] = NULL;
1422 fevPtr->nextPtr = firstFileEventPtr;
1423 firstFileEventPtr = fevPtr;
1424 Tk_CreateFileHandler2(fileno(f), FileEventProc,
1425 (ClientData) fevPtr);
1426 tcl_FileCloseProc = DeleteFileEvent;
1429 if (fevPtr->f == f) {
1435 * If we're just supposed to return the current script, do so.
1439 if (fevPtr->scripts[index] != NULL) {
1440 interp->result = fevPtr->scripts[index];
1446 * If we're supposed to delete the event handler, do so.
1449 if (argv[3][0] == 0) {
1450 if (fevPtr->scripts[index] != NULL) {
1451 fevPtr->interps[index] = NULL;
1452 ckfree(fevPtr->scripts[index]);
1453 fevPtr->scripts[index] = NULL;
1455 if ((fevPtr->scripts[0] == NULL) && (fevPtr->scripts[1] == NULL)) {
1456 if (firstFileEventPtr == fevPtr) {
1457 firstFileEventPtr = fevPtr->nextPtr;
1459 for (prevPtr = firstFileEventPtr; prevPtr->nextPtr != fevPtr;
1460 prevPtr = prevPtr->nextPtr) {
1461 /* Empty loop body. */
1463 prevPtr->nextPtr = fevPtr->nextPtr;
1465 Tk_DeleteFileHandler(fileno(fevPtr->f));
1466 ckfree((char *) fevPtr);
1472 * This is a new handler being created. Save its script.
1475 fevPtr->interps[index] = interp;
1476 if (fevPtr->scripts[index] != NULL) {
1477 ckfree(fevPtr->scripts[index]);
1479 fevPtr->scripts[index] = ckalloc((unsigned) (strlen(argv[3]) + 1));
1480 strcpy(fevPtr->scripts[index], argv[3]);
1485 *----------------------------------------------------------------------
1489 * This procedure is invoked by Tk's event loop to deal with file
1490 * event bindings created by the "fileevent" command.
1493 * The return value is TK_FILE_HANDLED if the file was ready and
1494 * a script was invoked to handle it. Otherwise an OR-ed combination
1495 * of TK_READABLE and TK_WRITABLE is returned, indicating the events
1496 * that should be checked in future calls to select.
1499 * Whatever the event script does.
1501 *----------------------------------------------------------------------
1505 FileEventProc(clientData, mask, flags)
1506 ClientData clientData; /* Pointer to FileEvent structure for file. */
1507 int mask; /* OR-ed combination of the bits TK_READABLE,
1508 * TK_WRITABLE, and TK_EXCEPTION, indicating
1509 * current state of file. */
1510 int flags; /* Flag bits passed to Tk_DoOneEvent;
1511 * contains bits such as TK_DONT_WAIT,
1512 * TK_X_EVENTS, Tk_FILE_EVENTS, etc. */
1514 FileEvent *fevPtr = (FileEvent *) clientData;
1518 int code, checkMask;
1520 if (!(flags & TK_FILE_EVENTS)) {
1525 * The code here is a little tricky, because the script for an
1526 * event could delete the event handler. Thus, after we call
1527 * Tcl_GlobalEval we can't use fevPtr anymore. We also have to
1528 * copy the script to make sure that it doesn't get freed while
1534 if (fevPtr->scripts[1] != NULL) {
1535 if (mask & TK_WRITABLE) {
1536 Tcl_DStringInit(&script);
1537 Tcl_DStringAppend(&script, fevPtr->scripts[1], -1);
1538 interp = fevPtr->interps[1];
1539 code = Tcl_GlobalEval(interp, Tcl_DStringValue(&script));
1540 Tcl_DStringFree(&script);
1541 if (code != TCL_OK) {
1544 return TK_FILE_HANDLED;
1546 checkMask |= TK_WRITABLE;
1549 if (fevPtr->scripts[0] != NULL) {
1550 if ((mask & TK_READABLE) || TK_READ_DATA_PENDING(f)) {
1551 Tcl_DStringInit(&script);
1552 Tcl_DStringAppend(&script, fevPtr->scripts[0], -1);
1553 interp = fevPtr->interps[0];
1554 code = Tcl_GlobalEval(interp, Tcl_DStringValue(&script));
1555 Tcl_DStringFree(&script);
1556 if (code != TCL_OK) {
1559 return TK_FILE_HANDLED;
1561 checkMask |= TK_READABLE;
1567 * An error occurred in the script, so we have to call
1568 * Tk_BackgroundError. However, it's possible that the file ready
1569 * condition didn't get cleared for the file, so we could end
1570 * up in an infinite loop if we're not careful. To be safe,
1571 * delete the event handler.
1576 Tcl_AddErrorInfo(interp,
1577 "\n (script bound to file event - binding deleted)");
1578 Tk_BackgroundError(interp);
1579 return TK_FILE_HANDLED;
1583 *----------------------------------------------------------------------
1585 * DeleteFileEvent --
1587 * This procedure is invoked to delete all file event handlers
1588 * for a file. For example, this is necessary if a file is closed,
1589 * or if an error occurs in a handler for a file.
1595 * The file event handler is removed, so it will never be invoked
1598 *----------------------------------------------------------------------
1603 FILE *f; /* Stdio structure describing open file. */
1605 register FileEvent *fevPtr;
1609 * See if there exists a file handler for the given file.
1612 for (prevPtr = NULL, fevPtr = firstFileEventPtr; ;
1613 prevPtr = fevPtr, fevPtr = fevPtr->nextPtr) {
1614 if (fevPtr == NULL) {
1617 if (fevPtr->f == f) {
1623 * Unlink it from the list, then free it.
1626 if (prevPtr == NULL) {
1627 firstFileEventPtr = fevPtr->nextPtr;
1629 prevPtr->nextPtr = fevPtr->nextPtr;
1631 Tk_DeleteFileHandler(fileno(fevPtr->f));
1632 if (fevPtr->scripts[0] != NULL) {
1633 ckfree(fevPtr->scripts[0]);
1635 if (fevPtr->scripts[1] != NULL) {
1636 ckfree(fevPtr->scripts[1]);
1638 ckfree((char *) fevPtr);
1642 *----------------------------------------------------------------------
1644 * TkEventCleanupProc --
1646 * This procedure is invoked whenever an interpreter is deleted.
1647 * It deletes any file events and after commands that refer to
1654 * File event handlers and after commands are removed.
1656 *----------------------------------------------------------------------
1661 TkEventCleanupProc(clientData, interp)
1662 ClientData clientData; /* Not used. */
1663 Tcl_Interp *interp; /* Interpreter that is being deleted. */
1665 FileEvent *fevPtr, *prevPtr, *nextPtr;
1666 AfterInfo *afterPtr, *prevAfterPtr, *nextAfterPtr;
1670 fevPtr = firstFileEventPtr;
1671 while (fevPtr != NULL) {
1672 for (i = 0; i < 2; i++) {
1673 if (fevPtr->interps[i] == interp) {
1674 fevPtr->interps[i] = NULL;
1675 ckfree((char *) fevPtr->scripts[i]);
1676 fevPtr->scripts[i] = NULL;
1679 if ((fevPtr->scripts[0] != NULL) || (fevPtr->scripts[1] != NULL)) {
1681 fevPtr = fevPtr->nextPtr;
1684 nextPtr = fevPtr->nextPtr;
1685 if (prevPtr == NULL) {
1686 firstFileEventPtr = nextPtr;
1688 prevPtr->nextPtr = nextPtr;
1690 Tk_DeleteFileHandler(fileno(fevPtr->f));
1691 ckfree((char *) fevPtr);
1695 prevAfterPtr = NULL;
1696 afterPtr = firstAfterPtr;
1697 while (afterPtr != NULL) {
1698 if (afterPtr->interp != interp) {
1699 prevAfterPtr = afterPtr;
1700 afterPtr = afterPtr->nextPtr;
1703 nextAfterPtr = afterPtr->nextPtr;
1704 if (prevAfterPtr == NULL) {
1705 firstAfterPtr = nextAfterPtr;
1707 prevAfterPtr->nextPtr = nextAfterPtr;
1709 if (afterPtr->token != NULL) {
1710 Tk_DeleteTimerHandler(afterPtr->token);
1712 Tk_CancelIdleCall(AfterProc, (ClientData) afterPtr);
1714 ckfree(afterPtr->command);
1715 ckfree((char *) afterPtr);
1716 afterPtr = nextAfterPtr;
1721 *----------------------------------------------------------------------
1725 * This procedure is invoked to process the "tkwait" Tcl command.
1726 * See the user documentation for details on what it does. This
1727 * is a modified version of tkwait with only the "variable"
1728 * option, suitable for use in stand-alone mode without the rest
1729 * of Tk. It's only used when Tk_EventInit has been called.
1732 * A standard Tcl result.
1735 * See the user documentation.
1737 *----------------------------------------------------------------------
1742 TkwaitCmd2(clientData, interp, argc, argv)
1743 ClientData clientData; /* Not used. */
1744 Tcl_Interp *interp; /* Current interpreter. */
1745 int argc; /* Number of arguments. */
1746 char **argv; /* Argument strings. */
1752 Tcl_AppendResult(interp, "wrong # args: should be \"",
1753 argv[0], " variable name\"", (char *) NULL);
1757 length = strlen(argv[1]);
1758 if ((c == 'v') && (strncmp(argv[1], "variable", length) == 0)
1760 Tcl_TraceVar(interp, argv[2],
1761 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1762 WaitVariableProc2, (ClientData) &done);
1767 Tcl_UntraceVar(interp, argv[2],
1768 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1769 WaitVariableProc2, (ClientData) &done);
1771 Tcl_AppendResult(interp, "bad option \"", argv[1],
1772 "\": must be variable", (char *) NULL);
1777 * Clear out the interpreter's result, since it may have been set
1778 * by event handlers.
1781 Tcl_ResetResult(interp);
1787 WaitVariableProc2(clientData, interp, name1, name2, flags)
1788 ClientData clientData; /* Pointer to integer to set to 1. */
1789 Tcl_Interp *interp; /* Interpreter containing variable. */
1790 char *name1; /* Name of variable. */
1791 char *name2; /* Second part of variable name. */
1792 int flags; /* Information about what happened. */
1794 int *donePtr = (int *) clientData;
1797 return (char *) NULL;
1801 *----------------------------------------------------------------------
1805 * This procedure is invoked to process the "update" Tcl command.
1806 * See the user documentation for details on what it does. This
1807 * is a modified version of the command that doesn't deal with
1808 * windows, suitable for use in stand-alone mode without the rest
1809 * of Tk. It's only used when Tk_EventInit has been called.
1812 * A standard Tcl result.
1815 * See the user documentation.
1817 *----------------------------------------------------------------------
1822 UpdateCmd2(clientData, interp, argc, argv)
1823 ClientData clientData; /* Not used. */
1824 Tcl_Interp *interp; /* Current interpreter. */
1825 int argc; /* Number of arguments. */
1826 char **argv; /* Argument strings. */
1831 flags = TK_DONT_WAIT|TK_FILE_EVENTS|TK_TIMER_EVENTS|TK_IDLE_EVENTS;
1832 } else if (argc == 2) {
1833 if (strncmp(argv[1], "idletasks", strlen(argv[1])) != 0) {
1834 Tcl_AppendResult(interp, "bad argument \"", argv[1],
1835 "\": must be idletasks", (char *) NULL);
1838 flags = TK_IDLE_EVENTS;
1840 Tcl_AppendResult(interp, "wrong # args: should be \"",
1841 argv[0], " ?idletasks?\"", (char *) NULL);
1846 * Handle all pending events.
1849 while (Tk_DoOneEvent(flags) != 0) {
1850 /* Empty loop body */
1854 * Must clear the interpreter's result because event handlers could
1855 * have executed commands.
1858 Tcl_ResetResult(interp);
1863 *----------------------------------------------------------------------
1867 * This procedure is invoked from Tcl_AppInit if the Tk event stuff
1868 * is being used by itself (without the rest of Tk) in an application.
1869 * It creates the "after" and "fileevent" commands.
1872 * Always returns TCL_OK.
1875 * New commands get added to interp.
1877 *----------------------------------------------------------------------
1881 Tk_EventInit(interp)
1882 Tcl_Interp *interp; /* Interpreter in which to set up
1883 * event-handling. */
1885 Tcl_CreateCommand(interp, "after", Tk_AfterCmd, (ClientData) NULL,
1887 Tcl_CreateCommand(interp, "fileevent", Tk_FileeventCmd, (ClientData) NULL,
1889 Tcl_CreateCommand(interp, "tkwait", TkwaitCmd2, (ClientData) NULL,
1891 Tcl_CreateCommand(interp, "update", UpdateCmd2, (ClientData) NULL,
1893 Tcl_CallWhenDeleted(interp, TkEventCleanupProc, (ClientData) NULL);
1897 #endif /* TCL_MINOR_VERSION == 7 && TCL_MINOR_VERSION <= 4 */