📄 tclnotify.c
字号:
* The handler for this event asked to defer it. Just go on to
* the next event.
*/
continue;
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* Tcl_GetServiceMode --
*
* This routine returns the current service mode of the notifier.
*
* Results:
* Returns either TCL_SERVICE_ALL or TCL_SERVICE_NONE.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Tcl_GetServiceMode(void)
{
if (!initialized) {
InitNotifier();
}
return notifier.serviceMode;
}
/*
*----------------------------------------------------------------------
*
* Tcl_SetServiceMode --
*
* This routine sets the current service mode of the notifier.
*
* Results:
* Returns the previous service mode.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Tcl_SetServiceMode(mode)
int mode; /* New service mode: TCL_SERVICE_ALL or
* TCL_SERVICE_NONE */
{
int oldMode;
if (!initialized) {
InitNotifier();
}
oldMode = notifier.serviceMode;
notifier.serviceMode = mode;
return oldMode;
}
/*
*----------------------------------------------------------------------
*
* Tcl_SetMaxBlockTime --
*
* This procedure is invoked by event sources to tell the notifier
* how long it may block the next time it blocks. The timePtr
* argument gives a maximum time; the actual time may be less if
* some other event source requested a smaller time.
*
* Results:
* None.
*
* Side effects:
* May reduce the length of the next sleep in the notifier.
*
*----------------------------------------------------------------------
*/
void
Tcl_SetMaxBlockTime(timePtr)
Tcl_Time *timePtr; /* Specifies a maximum elapsed time for
* the next blocking operation in the
* event notifier. */
{
if (!initialized) {
InitNotifier();
}
if (!notifier.blockTimeSet || (timePtr->sec < notifier.blockTime.sec)
|| ((timePtr->sec == notifier.blockTime.sec)
&& (timePtr->usec < notifier.blockTime.usec))) {
notifier.blockTime = *timePtr;
notifier.blockTimeSet = 1;
}
/*
* If we are called outside an event source traversal, set the
* timeout immediately.
*/
if (!notifier.inTraversal) {
if (notifier.blockTimeSet) {
Tcl_SetTimer(¬ifier.blockTime);
} else {
Tcl_SetTimer(NULL);
}
}
}
/*
*----------------------------------------------------------------------
*
* Tcl_DoOneEvent --
*
* Process a single event of some sort. If there's no work to
* do, wait for an event to occur, then process it.
*
* Results:
* The return value is 1 if the procedure actually found an event
* to process. If no processing occurred, then 0 is returned (this
* can happen if the TCL_DONT_WAIT flag is set or if there are no
* event handlers to wait for in the set specified by flags).
*
* Side effects:
* May delay execution of process while waiting for an event,
* unless TCL_DONT_WAIT is set in the flags argument. Event
* sources are invoked to check for and queue events. Event
* handlers may produce arbitrary side effects.
*
*----------------------------------------------------------------------
*/
int
Tcl_DoOneEvent(flags)
int flags; /* Miscellaneous flag values: may be any
* combination of TCL_DONT_WAIT,
* TCL_WINDOW_EVENTS, TCL_FILE_EVENTS,
* TCL_TIMER_EVENTS, TCL_IDLE_EVENTS, or
* others defined by event sources. */
{
int result = 0, oldMode;
EventSource *sourcePtr;
Tcl_Time *timePtr;
if (!initialized) {
InitNotifier();
}
/*
* The first thing we do is to service any asynchronous event
* handlers.
*/
if (Tcl_AsyncReady()) {
(void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
return 1;
}
/*
* No event flags is equivalent to TCL_ALL_EVENTS.
*/
if ((flags & TCL_ALL_EVENTS) == 0) {
flags |= TCL_ALL_EVENTS;
}
/*
* Set the service mode to none so notifier event routines won't
* try to service events recursively.
*/
oldMode = notifier.serviceMode;
notifier.serviceMode = TCL_SERVICE_NONE;
/*
* The core of this procedure is an infinite loop, even though
* we only service one event. The reason for this is that we
* may be processing events that don't do anything inside of Tcl.
*/
while (1) {
/*
* If idle events are the only things to service, skip the
* main part of the loop and go directly to handle idle
* events (i.e. don't wait even if TCL_DONT_WAIT isn't set).
*/
if ((flags & TCL_ALL_EVENTS) == TCL_IDLE_EVENTS) {
flags = TCL_IDLE_EVENTS|TCL_DONT_WAIT;
goto idleEvents;
}
/*
* Ask Tcl to service a queued event, if there are any.
*/
if (Tcl_ServiceEvent(flags)) {
result = 1;
break;
}
/*
* If TCL_DONT_WAIT is set, be sure to poll rather than
* blocking, otherwise reset the block time to infinity.
*/
if (flags & TCL_DONT_WAIT) {
notifier.blockTime.sec = 0;
notifier.blockTime.usec = 0;
notifier.blockTimeSet = 1;
} else {
notifier.blockTimeSet = 0;
}
/*
* Set up all the event sources for new events. This will
* cause the block time to be updated if necessary.
*/
notifier.inTraversal = 1;
for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
sourcePtr = sourcePtr->nextPtr) {
if (sourcePtr->setupProc) {
(sourcePtr->setupProc)(sourcePtr->clientData, flags);
}
}
notifier.inTraversal = 0;
if ((flags & TCL_DONT_WAIT) || notifier.blockTimeSet) {
timePtr = ¬ifier.blockTime;
} else {
timePtr = NULL;
}
/*
* Wait for a new event or a timeout. If Tcl_WaitForEvent
* returns -1, we should abort Tcl_DoOneEvent.
*/
result = Tcl_WaitForEvent(timePtr);
if (result < 0) {
result = 0;
break;
}
/*
* Check all the event sources for new events.
*/
for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
sourcePtr = sourcePtr->nextPtr) {
if (sourcePtr->checkProc) {
(sourcePtr->checkProc)(sourcePtr->clientData, flags);
}
}
/*
* Check for events queued by the notifier or event sources.
*/
if (Tcl_ServiceEvent(flags)) {
result = 1;
break;
}
/*
* We've tried everything at this point, but nobody we know
* about had anything to do. Check for idle events. If none,
* either quit or go back to the top and try again.
*/
idleEvents:
if (flags & TCL_IDLE_EVENTS) {
if (TclServiceIdle()) {
result = 1;
break;
}
}
if (flags & TCL_DONT_WAIT) {
break;
}
}
notifier.serviceMode = oldMode;
return result;
}
/*
*----------------------------------------------------------------------
*
* Tcl_ServiceAll --
*
* This routine checks all of the event sources, processes
* events that are on the Tcl event queue, and then calls the
* any idle handlers. Platform specific notifier callbacks that
* generate events should call this routine before returning to
* the system in order to ensure that Tcl gets a chance to
* process the new events.
*
* Results:
* Returns 1 if an event or idle handler was invoked, else 0.
*
* Side effects:
* Anything that an event or idle handler may do.
*
*----------------------------------------------------------------------
*/
int
Tcl_ServiceAll(void)
{
int result = 0;
EventSource *sourcePtr;
if (!initialized) {
InitNotifier();
}
if (notifier.serviceMode == TCL_SERVICE_NONE) {
return result;
}
/*
* We need to turn off event servicing like we to in Tcl_DoOneEvent,
* to avoid recursive calls.
*/
notifier.serviceMode = TCL_SERVICE_NONE;
/*
* Check async handlers first.
*/
if (Tcl_AsyncReady()) {
(void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
}
/*
* Make a single pass through all event sources, queued events,
* and idle handlers. Note that we wait to update the notifier
* timer until the end so we can avoid multiple changes.
*/
notifier.inTraversal = 1;
notifier.blockTimeSet = 0;
for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
sourcePtr = sourcePtr->nextPtr) {
if (sourcePtr->setupProc) {
(sourcePtr->setupProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
}
}
for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
sourcePtr = sourcePtr->nextPtr) {
if (sourcePtr->checkProc) {
(sourcePtr->checkProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
}
}
while (Tcl_ServiceEvent(0)) {
result = 1;
}
if (TclServiceIdle()) {
result = 1;
}
if (!notifier.blockTimeSet) {
Tcl_SetTimer(NULL);
} else {
Tcl_SetTimer(¬ifier.blockTime);
}
notifier.inTraversal = 0;
notifier.serviceMode = TCL_SERVICE_ALL;
return result;
}
/*
*----------------------------------------------------------------------
*
* PyTcl_WaitUntilEvent --
*
* New function to wait until a Tcl event is ready without
* actually handling the event. This is different than
* TclWaitForEvent(): that function doesn't call the event
* check routines, which is necessary for our purpose.
* We also can't use Tcl_DoOneEvent(TCL_DONT_WAIT), since that
* does too much: it handles the event. We want the *handling*
* of the event to be done with the Python lock held, but the
* *waiting* with the lock released.
*
* Since the event administration is not exported, our only
* choice is to use a modified copy of the file tclNotify.c,
* containing this additional function that makes the desired
* functionality available. It is mostly a stripped down version
* of the code in Tcl_DoOneEvent().
*
* This requires that you link with a static version of the Tcl
* library. On Windows/Mac, a custom compilation of Tcl may be
* required (I haven't tried this yet).
*
*----------------------------------------------------------------------
*/
int
PyTcl_WaitUntilEvent(void)
{
int flags = TCL_ALL_EVENTS;
int result = 0, oldMode;
EventSource *sourcePtr;
Tcl_Time *timePtr;
if (!initialized) {
InitNotifier();
}
/*
* The first thing we do is to service any asynchronous event
* handlers.
*/
if (Tcl_AsyncReady())
return 1;
/*
* Set the service mode to none so notifier event routines won't
* try to service events recursively.
*/
oldMode = notifier.serviceMode;
notifier.serviceMode = TCL_SERVICE_NONE;
notifier.blockTimeSet = 0;
/*
* Set up all the event sources for new events. This will
* cause the block time to be updated if necessary.
*/
notifier.inTraversal = 1;
for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
sourcePtr = sourcePtr->nextPtr) {
if (sourcePtr->setupProc) {
(sourcePtr->setupProc)(sourcePtr->clientData, flags);
}
}
notifier.inTraversal = 0;
timePtr = NULL;
/*
* Wait for a new event or a timeout. If Tcl_WaitForEvent
* returns -1, we should abort Tcl_DoOneEvent.
*/
result = Tcl_WaitForEvent(timePtr);
if (result < 0)
return 0;
/*
* Check all the event sources for new events.
*/
for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
sourcePtr = sourcePtr->nextPtr) {
if (sourcePtr->checkProc) {
(sourcePtr->checkProc)(sourcePtr->clientData, flags);
}
}
notifier.serviceMode = oldMode;
return result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -