📄 tclxtnotify.c
字号:
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;
if (!initialized) {
InitNotifier();
}
TclSetAppContext(NULL);
for (filePtr = notifier.firstFileHandlerPtr; filePtr != NULL;
filePtr = filePtr->nextPtr) {
if (filePtr->fd == fd) {
break;
}
}
if (filePtr == NULL) {
filePtr = (FileHandler*) ckalloc(sizeof(FileHandler));
filePtr->fd = fd;
filePtr->read = 0;
filePtr->write = 0;
filePtr->except = 0;
filePtr->readyMask = 0;
filePtr->mask = 0;
filePtr->nextPtr = notifier.firstFileHandlerPtr;
notifier.firstFileHandlerPtr = filePtr;
}
filePtr->proc = proc;
filePtr->clientData = clientData;
/*
* Register the file with the Xt notifier, if it hasn't been done yet.
*/
if (mask & TCL_READABLE) {
if (!(filePtr->mask & TCL_READABLE)) {
filePtr->read =
XtAppAddInput(notifier.appContext, fd, XtInputReadMask,
FileProc, filePtr);
}
} else {
if (filePtr->mask & TCL_READABLE) {
XtRemoveInput(filePtr->read);
}
}
if (mask & TCL_WRITABLE) {
if (!(filePtr->mask & TCL_WRITABLE)) {
filePtr->write =
XtAppAddInput(notifier.appContext, fd, XtInputWriteMask,
FileProc, filePtr);
}
} else {
if (filePtr->mask & TCL_WRITABLE) {
XtRemoveInput(filePtr->write);
}
}
if (mask & TCL_EXCEPTION) {
if (!(filePtr->mask & TCL_EXCEPTION)) {
filePtr->except =
XtAppAddInput(notifier.appContext, fd, XtInputExceptMask,
FileProc, filePtr);
}
} else {
if (filePtr->mask & TCL_EXCEPTION) {
XtRemoveInput(filePtr->except);
}
}
filePtr->mask = mask;
}
/*
*----------------------------------------------------------------------
*
* 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;
if (!initialized) {
InitNotifier();
}
TclSetAppContext(NULL);
/*
* 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;
}
}
/*
* Clean up information in the callback record.
*/
if (prevPtr == NULL) {
notifier.firstFileHandlerPtr = filePtr->nextPtr;
} else {
prevPtr->nextPtr = filePtr->nextPtr;
}
if (filePtr->mask & TCL_READABLE) {
XtRemoveInput(filePtr->read);
}
if (filePtr->mask & TCL_WRITABLE) {
XtRemoveInput(filePtr->write);
}
if (filePtr->mask & TCL_EXCEPTION) {
XtRemoveInput(filePtr->except);
}
ckfree((char *) filePtr);
}
/*
*----------------------------------------------------------------------
*
* FileProc --
*
* These procedures are called by Xt when a file becomes readable,
* writable, or has an exception.
*
* Results:
* None.
*
* Side effects:
* Makes an entry on the Tcl event queue if the event is
* interesting.
*
*----------------------------------------------------------------------
*/
static void
FileProc(clientData, fd, id)
caddr_t clientData;
int *fd;
XtInputId *id;
{
FileHandler *filePtr = (FileHandler *)clientData;
FileHandlerEvent *fileEvPtr;
int mask = 0;
/*
* Determine which event happened.
*/
if (*id == filePtr->read) {
mask = TCL_READABLE;
} else if (*id == filePtr->write) {
mask = TCL_WRITABLE;
} else if (*id == filePtr->except) {
mask = TCL_EXCEPTION;
}
/*
* Ignore unwanted or duplicate events.
*/
if (!(filePtr->mask & mask) || (filePtr->readyMask & mask)) {
return;
}
/*
* This is an interesting event, so put it onto the event queue.
*/
filePtr->readyMask |= mask;
fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent));
fileEvPtr->header.proc = FileHandlerEventProc;
fileEvPtr->fd = filePtr->fd;
Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
/*
* Process events on the Tcl event queue before returning to Xt.
*/
Tcl_ServiceAll();
}
/*
*----------------------------------------------------------------------
*
* 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_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 without blocking.
*
* Results:
* Returns 1 if an event was found, else 0. This ensures that
* Tcl_DoOneEvent will return 1, even if the event is handled
* by non-Tcl code.
*
* Side effects:
* Queues file events that are detected by the select.
*
*----------------------------------------------------------------------
*/
int
Tcl_WaitForEvent(
Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
int timeout;
if (!initialized) {
InitNotifier();
}
TclSetAppContext(NULL);
if (timePtr) {
timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
if (timeout == 0) {
if (XtAppPending(notifier.appContext)) {
goto process;
} else {
return 0;
}
} else {
Tcl_SetTimer(timePtr);
}
}
process:
XtAppProcessEvent(notifier.appContext, XtIMAll);
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -