diff options
author | Jack Jansen <jack.jansen@cwi.nl> | 1998-08-18 14:51:27 (GMT) |
---|---|---|
committer | Jack Jansen <jack.jansen@cwi.nl> | 1998-08-18 14:51:27 (GMT) |
commit | b0195ec9c136300bcd65d89bfdf287a98af6c7de (patch) | |
tree | 0d7c380f43709f32cfc2e86d15ee818d02056bfb /Mac/tclmods | |
parent | 0072bfb12673b46803eb5ea01f9b7a351b5e840a (diff) | |
download | cpython-b0195ec9c136300bcd65d89bfdf287a98af6c7de.zip cpython-b0195ec9c136300bcd65d89bfdf287a98af6c7de.tar.gz cpython-b0195ec9c136300bcd65d89bfdf287a98af6c7de.tar.bz2 |
Putting TCL mods for Python under CVS.
Diffstat (limited to 'Mac/tclmods')
-rw-r--r-- | Mac/tclmods/license-terms.txt | 39 | ||||
-rw-r--r-- | Mac/tclmods/tclMacNotify.c | 425 | ||||
-rw-r--r-- | Mac/tclmods/tclSelectNotify.c | 503 |
3 files changed, 967 insertions, 0 deletions
diff --git a/Mac/tclmods/license-terms.txt b/Mac/tclmods/license-terms.txt new file mode 100644 index 0000000..96ad966 --- /dev/null +++ b/Mac/tclmods/license-terms.txt @@ -0,0 +1,39 @@ +This software is copyrighted by the Regents of the University of +California, Sun Microsystems, Inc., and other parties. The following +terms apply to all files associated with the software unless explicitly +disclaimed in individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, provided +that existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written agreement, +license, or royalty fee is required for any of the authorized uses. +Modifications to this software may be copyrighted by their authors +and need not follow the licensing terms described here, provided that +the new terms are clearly indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" +in the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +are acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. diff --git a/Mac/tclmods/tclMacNotify.c b/Mac/tclmods/tclMacNotify.c new file mode 100644 index 0000000..140dadb --- /dev/null +++ b/Mac/tclmods/tclMacNotify.c @@ -0,0 +1,425 @@ +/* + * tclMacNotify.c -- + * + * This file contains Macintosh-specific procedures for the notifier, + * which is the lowest-level part of the Tcl event loop. This file + * works together with ../generic/tclNotify.c. + * + * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tclMacNotify.c 1.36 97/05/07 19:09:29 + */ + +#include "tclInt.h" +#include "tclPort.h" +#include "tclMac.h" +#include "tclMacInt.h" +#include <signal.h> +#include <Events.h> +#include <LowMem.h> +#include <Processes.h> +#include <Timer.h> + + +/* + * This is necessary to work around a bug in Apple's Universal header files + * for the CFM68K libraries. + */ + +#ifdef __CFM68K__ +#undef GetEventQueue +extern pascal QHdrPtr GetEventQueue(void) + THREEWORDINLINE(0x2EBC, 0x0000, 0x014A); +#pragma import list GetEventQueue +#define GetEvQHdr() GetEventQueue() +#endif + +/* + * The follwing static indicates whether this module has been initialized. + */ + +static int initialized = 0; + +/* + * The following structure contains the state information for the + * notifier module. + */ + +static struct { + int timerActive; /* 1 if timer is running. */ + Tcl_Time timer; /* Time when next timer event is expected. */ + int flags; /* OR'ed set of flags defined below. */ + Point lastMousePosition; /* Last known mouse location. */ + RgnHandle utilityRgn; /* Region used as the mouse region for + * WaitNextEvent and the update region when + * checking for events. */ + Tcl_MacConvertEventPtr eventProcPtr; + /* This pointer holds the address of the + * function that will handle all incoming + * Macintosh events. */ +} notifier; + +/* + * The following defines are used in the flags field of the notifier struct. + */ + +#define NOTIFY_IDLE (1<<1) /* Tcl_ServiceIdle should be called. */ +#define NOTIFY_TIMER (1<<2) /* Tcl_ServiceTimer should be called. */ + +/* + * Prototypes for procedures that are referenced only in this file: + */ + +static int HandleMacEvents _ANSI_ARGS_((void)); +static void InitNotifier _ANSI_ARGS_((void)); +static void NotifierExitHandler _ANSI_ARGS_(( + ClientData clientData)); + +/* + *---------------------------------------------------------------------- + * + * InitNotifier -- + * + * Initializes the notifier structure. + * + * Results: + * None. + * + * Side effects: + * Creates a new exit handler. + * + *---------------------------------------------------------------------- + */ + +static void +InitNotifier(void) +{ + initialized = 1; + memset(¬ifier, 0, sizeof(notifier)); + Tcl_CreateExitHandler(NotifierExitHandler, NULL); +} + +/* + *---------------------------------------------------------------------- + * + * NotifierExitHandler -- + * + * This function is called to cleanup the notifier state before + * Tcl is unloaded. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +NotifierExitHandler( + ClientData clientData) /* Not used. */ +{ + initialized = 0; +} + +/* + *---------------------------------------------------------------------- + * + * HandleMacEvents -- + * + * This function checks for events from the Macintosh event queue. + * + * Results: + * Returns 1 if event found, 0 otherwise. + * + * Side effects: + * Pulls events off of the Mac event queue and then calls + * convertEventProc. + * + *---------------------------------------------------------------------- + */ + +static int +HandleMacEvents(void) +{ + EventRecord theEvent; + int eventFound = 0, needsUpdate = 0; + Point currentMouse; + WindowRef windowRef; + Rect mouseRect; + + /* + * Check for mouse moved events. These events aren't placed on the + * system event queue unless we call WaitNextEvent. + */ + + GetGlobalMouse(¤tMouse); + if ((notifier.eventProcPtr != NULL) && + !EqualPt(currentMouse, notifier.lastMousePosition)) { + notifier.lastMousePosition = currentMouse; + theEvent.what = nullEvent; + if ((*notifier.eventProcPtr)(&theEvent) == true) { + eventFound = 1; + } + } + + /* + * Check for update events. Since update events aren't generated + * until we call GetNextEvent, we may need to force a call to + * GetNextEvent, even if the queue is empty. + */ + + for (windowRef = FrontWindow(); windowRef != NULL; + windowRef = GetNextWindow(windowRef)) { + GetWindowUpdateRgn(windowRef, notifier.utilityRgn); + if (!EmptyRgn(notifier.utilityRgn)) { + needsUpdate = 1; + break; + } + } + + /* + * Process events from the OS event queue. + */ + + while (needsUpdate || (GetEvQHdr()->qHead != NULL)) { + GetGlobalMouse(¤tMouse); + SetRect(&mouseRect, currentMouse.h, currentMouse.v, + currentMouse.h + 1, currentMouse.v + 1); + RectRgn(notifier.utilityRgn, &mouseRect); + + WaitNextEvent(everyEvent, &theEvent, 5, notifier.utilityRgn); + needsUpdate = 0; + if ((notifier.eventProcPtr != NULL) + && ((*notifier.eventProcPtr)(&theEvent) == true)) { + eventFound = 1; + } + } + + return eventFound; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_SetTimer -- + * + * This procedure sets the current notifier timer value. The + * notifier will ensure that Tcl_ServiceAll() is called after + * the specified interval, even if no events have occurred. + * + * Results: + * None. + * + * Side effects: + * Replaces any previous timer. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_SetTimer( + Tcl_Time *timePtr) /* New value for interval timer. */ +{ + if (!timePtr) { + notifier.timerActive = 0; + } else { + /* + * Compute when the timer should fire. + */ + + TclpGetTime(¬ifier.timer); + notifier.timer.sec += timePtr->sec; + notifier.timer.usec += timePtr->usec; + if (notifier.timer.usec >= 1000000) { + notifier.timer.usec -= 1000000; + notifier.timer.sec += 1; + } + notifier.timerActive = 1; + } +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_WaitForEvent -- + * + * This function is called by Tcl_DoOneEvent to wait for new + * events on the message queue. If the block time is 0, then + * Tcl_WaitForEvent just polls the event queue without blocking. + * + * Results: + * Always returns 0. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_WaitForEvent( + Tcl_Time *timePtr) /* Maximum block time. */ +{ + int found; + EventRecord macEvent; + long sleepTime = 5; + long ms; + Point currentMouse; + void * timerToken; + Rect mouseRect; + + /* + * Compute the next timeout value. + */ + + if (!timePtr) { + ms = INT_MAX; + } else { + ms = (timePtr->sec * 1000) + (timePtr->usec / 1000); + } + timerToken = TclMacStartTimer((long) ms); + + /* + * Poll the Mac event sources. This loop repeats until something + * happens: a timeout, a socket event, mouse motion, or some other + * window event. Note that we don't call WaitNextEvent if another + * event is found to avoid context switches. This effectively gives + * events coming in via WaitNextEvent a slightly lower priority. + */ + + found = 0; + if (notifier.utilityRgn == NULL) { + notifier.utilityRgn = NewRgn(); + } + + while (!found) { + /* + * Check for generated and queued events. + */ + + if (HandleMacEvents()) { + found = 1; + } + + /* + * Check for time out. + */ + + if (!found && TclMacTimerExpired(timerToken)) { + found = 1; + } + + /* + * Mod by Jack: poll for select() events. Code is in TclSelectNotify.c + */ + { + int Tcl_PollSelectEvent(void); + if (!found && Tcl_PollSelectEvent()) + found = 1; + } + + /* + * Check for window events. We may receive a NULL event for + * various reasons. 1) the timer has expired, 2) a mouse moved + * event is occuring or 3) the os is giving us time for idle + * events. Note that we aren't sharing the processor very + * well here. We really ought to do a better job of calling + * WaitNextEvent for time slicing purposes. + */ + + if (!found) { + /* + * Set up mouse region so we will wake if the mouse is moved. + * We do this by defining the smallest possible region around + * the current mouse position. + */ + + GetGlobalMouse(¤tMouse); + SetRect(&mouseRect, currentMouse.h, currentMouse.v, + currentMouse.h + 1, currentMouse.v + 1); + RectRgn(notifier.utilityRgn, &mouseRect); + + WaitNextEvent(everyEvent, &macEvent, sleepTime, + notifier.utilityRgn); + + if (notifier.eventProcPtr != NULL) { + if ((*notifier.eventProcPtr)(&macEvent) == true) { + found = 1; + } + } + } + } + TclMacRemoveTimer(timerToken); + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_Sleep -- + * + * Delay execution for the specified number of milliseconds. This + * is not a very good call to make. It will block the system - + * you will not even be able to switch applications. + * + * Results: + * None. + * + * Side effects: + * Time passes. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_Sleep( + int ms) /* Number of milliseconds to sleep. */ +{ + EventRecord dummy; + void *timerToken; + + if (ms <= 0) { + return; + } + + timerToken = TclMacStartTimer((long) ms); + while (1) { + WaitNextEvent(0, &dummy, (ms / 16.66) + 1, NULL); + + if (TclMacTimerExpired(timerToken)) { + break; + } + } + TclMacRemoveTimer(timerToken); +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_MacSetEventProc -- + * + * This function sets the event handling procedure for the + * application. This function will be passed all incoming Mac + * events. This function usually controls the console or some + * other entity like Tk. + * + * Results: + * None. + * + * Side effects: + * Changes the event handling function. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_MacSetEventProc( + Tcl_MacConvertEventPtr procPtr) +{ + notifier.eventProcPtr = procPtr; +} diff --git a/Mac/tclmods/tclSelectNotify.c b/Mac/tclmods/tclSelectNotify.c new file mode 100644 index 0000000..ea35fc6 --- /dev/null +++ b/Mac/tclmods/tclSelectNotify.c @@ -0,0 +1,503 @@ +/* + * tclSelectNotify.c -- + * + * Partial even handling, select only. This file is adapted from TclUnixNotify.c, and + * meant as an add-in for Mac (and possibly Windows) environments where select *is* available. + * TclMacNotify.c works together with this file. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tclUnixNotfy.c 1.42 97/07/02 20:55:44 + */ + +#if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__) + #pragma import on +#endif + +#include <unistd.h> + +#if defined(__CFM68K__) && !defined(__USING_STATIC_LIBS__) + #pragma import reset +#endif + +#include "tclInt.h" +#include "tclPort.h" +#include <signal.h> + +#ifndef MASK_SIZE +#define MASK_SIZE howmany(FD_SETSIZE, NFDBITS) +#endif +#ifndef SELECT_MASK +#define SELECT_MASK fd_set +#endif + +/* Prototype (too lazy to create new .h) */ +int Tcl_PollSelectEvent(void); + +/* + * This structure is used to keep track of the notifier info for a + * a registered file. + */ + +typedef struct FileHandler { + int fd; + int mask; /* Mask of desired events: TCL_READABLE, + * etc. */ + int readyMask; /* Mask of events that have been seen since the + * last time file handlers were invoked for + * this file. */ + Tcl_FileProc *proc; /* Procedure to call, in the style of + * Tcl_CreateFileHandler. */ + ClientData clientData; /* Argument to pass to proc. */ + struct FileHandler *nextPtr;/* Next in list of all files we care about. */ +} FileHandler; + +/* + * The following structure is what is added to the Tcl event queue when + * file handlers are ready to fire. + */ + +typedef struct FileHandlerEvent { + Tcl_Event header; /* Information that is standard for + * all events. */ + int fd; /* File descriptor that is ready. Used + * to find the FileHandler structure for + * the file (can't point directly to the + * FileHandler structure because it could + * go away while the event is queued). */ +} FileHandlerEvent; + +/* + * The following static structure contains the state information for the + * select based implementation of the Tcl notifier. + */ + +static struct { + FileHandler *firstFileHandlerPtr; + /* Pointer to head of file handler list. */ + fd_mask checkMasks[3*MASK_SIZE]; + /* This array is used to build up the masks + * to be used in the next call to select. + * Bits are set in response to calls to + * Tcl_CreateFileHandler. */ + fd_mask readyMasks[3*MASK_SIZE]; + /* This array reflects the readable/writable + * conditions that were found to exist by the + * last call to select. */ + int numFdBits; /* Number of valid bits in checkMasks + * (one more than highest fd for which + * Tcl_WatchFile has been called). */ +} notifier; + +/* + * The following static indicates whether this module has been initialized. + */ + +static int initialized = 0; + +/* + * Static routines defined in this file. + */ + +static void InitNotifier _ANSI_ARGS_((void)); +static void NotifierExitHandler _ANSI_ARGS_(( + ClientData clientData)); +static int FileHandlerEventProc _ANSI_ARGS_((Tcl_Event *evPtr, + int flags)); + +/* + *---------------------------------------------------------------------- + * + * InitNotifier -- + * + * Initializes the notifier state. + * + * Results: + * None. + * + * Side effects: + * Creates a new exit handler. + * + *---------------------------------------------------------------------- + */ + +static void +InitNotifier() +{ + initialized = 1; + memset(¬ifier, 0, sizeof(notifier)); + Tcl_CreateExitHandler(NotifierExitHandler, NULL); +} + +/* + *---------------------------------------------------------------------- + * + * NotifierExitHandler -- + * + * This function is called to cleanup the notifier state before + * Tcl is unloaded. + * + * Results: + * None. + * + * Side effects: + * Destroys the notifier window. + * + *---------------------------------------------------------------------- + */ + +static void +NotifierExitHandler(clientData) + ClientData clientData; /* Not used. */ +{ + initialized = 0; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_CreateFileHandler -- + * + * This procedure registers a file handler with the Xt notifier. + * + * Results: + * None. + * + * Side effects: + * Creates a new file handler structure and registers one or more + * input procedures with Xt. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_CreateFileHandler(fd, mask, proc, clientData) + int fd; /* Handle of stream to watch. */ + int mask; /* OR'ed combination of TCL_READABLE, + * TCL_WRITABLE, and TCL_EXCEPTION: + * indicates conditions under which + * proc should be called. */ + Tcl_FileProc *proc; /* Procedure to call for each + * selected event. */ + ClientData clientData; /* Arbitrary data to pass to proc. */ +{ + FileHandler *filePtr; + int index, bit; + + if (!initialized) { + InitNotifier(); + } + + for (filePtr = notifier.firstFileHandlerPtr; filePtr != NULL; + filePtr = filePtr->nextPtr) { + if (filePtr->fd == fd) { + break; + } + } + if (filePtr == NULL) { + filePtr = (FileHandler*) ckalloc(sizeof(FileHandler)); /* MLK */ + filePtr->fd = fd; + filePtr->readyMask = 0; + filePtr->nextPtr = notifier.firstFileHandlerPtr; + notifier.firstFileHandlerPtr = filePtr; + } + filePtr->proc = proc; + filePtr->clientData = clientData; + filePtr->mask = mask; + + /* + * Update the check masks for this file. + */ + + index = fd/(NBBY*sizeof(fd_mask)); + bit = 1 << (fd%(NBBY*sizeof(fd_mask))); + if (mask & TCL_READABLE) { + notifier.checkMasks[index] |= bit; + } else { + notifier.checkMasks[index] &= ~bit; + } + if (mask & TCL_WRITABLE) { + (notifier.checkMasks+MASK_SIZE)[index] |= bit; + } else { + (notifier.checkMasks+MASK_SIZE)[index] &= ~bit; + } + if (mask & TCL_EXCEPTION) { + (notifier.checkMasks+2*(MASK_SIZE))[index] |= bit; + } else { + (notifier.checkMasks+2*(MASK_SIZE))[index] &= ~bit; + } + if (notifier.numFdBits <= fd) { + notifier.numFdBits = fd+1; + } +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_DeleteFileHandler -- + * + * Cancel a previously-arranged callback arrangement for + * a file. + * + * Results: + * None. + * + * Side effects: + * If a callback was previously registered on file, remove it. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_DeleteFileHandler(fd) + int fd; /* Stream id for which to remove callback procedure. */ +{ + FileHandler *filePtr, *prevPtr; + int index, bit, mask, i; + + if (!initialized) { + InitNotifier(); + } + + /* + * Find the entry for the given file (and return if there + * isn't one). + */ + + for (prevPtr = NULL, filePtr = notifier.firstFileHandlerPtr; ; + prevPtr = filePtr, filePtr = filePtr->nextPtr) { + if (filePtr == NULL) { + return; + } + if (filePtr->fd == fd) { + break; + } + } + + /* + * Update the check masks for this file. + */ + + index = fd/(NBBY*sizeof(fd_mask)); + bit = 1 << (fd%(NBBY*sizeof(fd_mask))); + + if (filePtr->mask & TCL_READABLE) { + notifier.checkMasks[index] &= ~bit; + } + if (filePtr->mask & TCL_WRITABLE) { + (notifier.checkMasks+MASK_SIZE)[index] &= ~bit; + } + if (filePtr->mask & TCL_EXCEPTION) { + (notifier.checkMasks+2*(MASK_SIZE))[index] &= ~bit; + } + + /* + * Find current max fd. + */ + + if (fd+1 == notifier.numFdBits) { + for (notifier.numFdBits = 0; index >= 0; index--) { + mask = notifier.checkMasks[index] + | (notifier.checkMasks+MASK_SIZE)[index] + | (notifier.checkMasks+2*(MASK_SIZE))[index]; + if (mask) { + for (i = (NBBY*sizeof(fd_mask)); i > 0; i--) { + if (mask & (1 << (i-1))) { + break; + } + } + notifier.numFdBits = index * (NBBY*sizeof(fd_mask)) + i; + break; + } + } + } + + /* + * Clean up information in the callback record. + */ + + if (prevPtr == NULL) { + notifier.firstFileHandlerPtr = filePtr->nextPtr; + } else { + prevPtr->nextPtr = filePtr->nextPtr; + } + ckfree((char *) filePtr); +} + +/* + *---------------------------------------------------------------------- + * + * FileHandlerEventProc -- + * + * This procedure is called by Tcl_ServiceEvent when a file event + * reaches the front of the event queue. This procedure is + * responsible for actually handling the event by invoking the + * callback for the file handler. + * + * Results: + * Returns 1 if the event was handled, meaning it should be removed + * from the queue. Returns 0 if the event was not handled, meaning + * it should stay on the queue. The only time the event isn't + * handled is if the TCL_FILE_EVENTS flag bit isn't set. + * + * Side effects: + * Whatever the file handler's callback procedure does. + * + *---------------------------------------------------------------------- + */ + +static int +FileHandlerEventProc(evPtr, flags) + Tcl_Event *evPtr; /* Event to service. */ + int flags; /* Flags that indicate what events to + * handle, such as TCL_FILE_EVENTS. */ +{ + FileHandler *filePtr; + FileHandlerEvent *fileEvPtr = (FileHandlerEvent *) evPtr; + int mask; + + if (!(flags & TCL_FILE_EVENTS)) { + return 0; + } + + /* + * Search through the file handlers to find the one whose handle matches + * the event. We do this rather than keeping a pointer to the file + * handler directly in the event, so that the handler can be deleted + * while the event is queued without leaving a dangling pointer. + */ + + for (filePtr = notifier.firstFileHandlerPtr; filePtr != NULL; + filePtr = filePtr->nextPtr) { + if (filePtr->fd != fileEvPtr->fd) { + continue; + } + + /* + * The code is tricky for two reasons: + * 1. The file handler's desired events could have changed + * since the time when the event was queued, so AND the + * ready mask with the desired mask. + * 2. The file could have been closed and re-opened since + * the time when the event was queued. This is why the + * ready mask is stored in the file handler rather than + * the queued event: it will be zeroed when a new + * file handler is created for the newly opened file. + */ + + mask = filePtr->readyMask & filePtr->mask; + filePtr->readyMask = 0; + if (mask != 0) { + (*filePtr->proc)(filePtr->clientData, mask); + } + break; + } + return 1; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_PollSelectEvent -- + * + * This function is called by Tcl_WaitForEvent to wait for new + * events on the message queue. If the block time is 0, then + * Tcl_WaitForEvent just polls without blocking. + * + * Results: + * Returns 1 if any event handled, 0 otherwise. + * + * Side effects: + * Queues file events that are detected by the select. + * + *---------------------------------------------------------------------- + */ + +int +Tcl_PollSelectEvent(void) +{ + FileHandler *filePtr; + FileHandlerEvent *fileEvPtr; + struct timeval timeout, *timeoutPtr; + int bit, index, mask, numFound; + + if (!initialized) { + InitNotifier(); + } + + /* + * Set up the timeout structure. + */ + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + timeoutPtr = &timeout; + + memcpy((VOID *) notifier.readyMasks, (VOID *) notifier.checkMasks, + 3*MASK_SIZE*sizeof(fd_mask)); + numFound = select(notifier.numFdBits, + (SELECT_MASK *) ¬ifier.readyMasks[0], + (SELECT_MASK *) ¬ifier.readyMasks[MASK_SIZE], + (SELECT_MASK *) ¬ifier.readyMasks[2*MASK_SIZE], timeoutPtr); + + /* + * Some systems don't clear the masks after an error, so + * we have to do it here. + */ + + if (numFound == -1) { + memset((VOID *) notifier.readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask)); + } + + /* + * Return if nothing to do. + */ + if ( numFound == 0 ) + return 0; + + /* + * Queue all detected file events before returning. + */ + + for (filePtr = notifier.firstFileHandlerPtr; + (filePtr != NULL) && (numFound > 0); + filePtr = filePtr->nextPtr) { + index = filePtr->fd / (NBBY*sizeof(fd_mask)); + bit = 1 << (filePtr->fd % (NBBY*sizeof(fd_mask))); + mask = 0; + + if (notifier.readyMasks[index] & bit) { + mask |= TCL_READABLE; + } + if ((notifier.readyMasks+MASK_SIZE)[index] & bit) { + mask |= TCL_WRITABLE; + } + if ((notifier.readyMasks+2*(MASK_SIZE))[index] & bit) { + mask |= TCL_EXCEPTION; + } + + if (!mask) { + continue; + } else { + numFound--; + } + + /* + * Don't bother to queue an event if the mask was previously + * non-zero since an event must still be on the queue. + */ + + if (filePtr->readyMask == 0) { + fileEvPtr = (FileHandlerEvent *) ckalloc( + sizeof(FileHandlerEvent)); + fileEvPtr->header.proc = FileHandlerEventProc; + fileEvPtr->fd = filePtr->fd; + Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL); + } + filePtr->readyMask = mask; + } + return 1; +} |