📄 tclxtnotify.c
字号:
/*
* tclXtNotify.c --
*
* This file contains the notifier driver implementation for the
* Xt intrinsics.
*
* Copyright (c) 1997 by 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: @(#) tclXtNotify.c 1.10 97/09/15 13:24:21
*/
#include <X11/Intrinsic.h>
#include <tclInt.h>
/*
* 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; /* Events that have been seen since the
last time FileHandlerEventProc was called
for this file. */
XtInputId read; /* Xt read callback handle. */
XtInputId write; /* Xt write callback handle. */
XtInputId except; /* Xt exception callback handle. */
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
* Xt based implementation of the Tcl notifier.
*/
static struct NotifierState {
XtAppContext appContext; /* The context used by the Xt
* notifier. Can be set with
* TclSetAppContext. */
int appContextCreated; /* Was it created by us? */
XtIntervalId currentTimeout; /* Handle of current timer. */
FileHandler *firstFileHandlerPtr; /* Pointer to head of file handler
* list. */
} notifier;
/*
* The following static indicates whether this module has been initialized.
*/
static int initialized = 0;
/*
* Static routines defined in this file.
*/
static int FileHandlerEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
int flags));
static void FileProc _ANSI_ARGS_((caddr_t clientData,
int *source, XtInputId *id));
static void InitNotifier _ANSI_ARGS_((void));
static void NotifierExitHandler _ANSI_ARGS_((
ClientData clientData));
static void TimerProc _ANSI_ARGS_((caddr_t clientData,
XtIntervalId *id));
/*
* Functions defined in this file for use by users of the Xt Notifier:
*/
EXTERN XtAppContext TclSetAppContext _ANSI_ARGS_((XtAppContext ctx));
/*
*----------------------------------------------------------------------
*
* TclSetAppContext --
*
* Set the notifier application context.
*
* Results:
* None.
*
* Side effects:
* Sets the application context used by the notifier. Panics if
* the context is already set when called.
*
*----------------------------------------------------------------------
*/
XtAppContext
TclSetAppContext(appContext)
XtAppContext appContext;
{
if (!initialized) {
InitNotifier();
}
/*
* If we already have a context we check whether we were asked to set a
* new context. If so, we panic because we try to prevent switching
* contexts by mistake. Otherwise, we return the one we have.
*/
if (notifier.appContext != NULL) {
if (appContext != NULL) {
/*
* We already have a context. We do not allow switching contexts
* after initialization, so we panic.
*/
panic("TclSetAppContext: multiple application contexts");
}
} else {
/*
* If we get here we have not yet gotten a context, so either create
* one or use the one supplied by our caller.
*/
if (appContext == NULL) {
/*
* We must create a new context and tell our caller what it is, so
* she can use it too.
*/
notifier.appContext = XtCreateApplicationContext();
notifier.appContextCreated = 1;
} else {
/*
* Otherwise we remember the context that our caller gave us
* and use it.
*/
notifier.appContextCreated = 0;
notifier.appContext = appContext;
}
}
return notifier.appContext;
}
/*
*----------------------------------------------------------------------
*
* InitNotifier --
*
* Initializes the notifier state.
*
* Results:
* None.
*
* Side effects:
* Creates a new exit handler.
*
*----------------------------------------------------------------------
*/
static void
InitNotifier(void)
{
/*
* Only reinitialize if we are not in exit handling. The notifier
* can get reinitialized after its own exit handler has run, because
* of exit handlers for the I/O and timer sub-systems (order dependency).
*/
if (TclInExit()) {
return;
}
/*
* DO NOT create the application context yet; doing so would prevent
* external applications from setting it for us to their own ones.
*/
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) /* Not used. */
{
if (notifier.currentTimeout != 0) {
XtRemoveTimeOut(notifier.currentTimeout);
}
for (; notifier.firstFileHandlerPtr != NULL; ) {
Tcl_DeleteFileHandler(notifier.firstFileHandlerPtr->fd);
}
if (notifier.appContextCreated) {
XtDestroyApplicationContext(notifier.appContext);
notifier.appContextCreated = 0;
notifier.appContext = NULL;
}
initialized = 0;
}
/*
*----------------------------------------------------------------------
*
* Tcl_SetTimer --
*
* This procedure sets the current notifier timeout value.
*
* Results:
* None.
*
* Side effects:
* Replaces any previous timer.
*
*----------------------------------------------------------------------
*/
void
Tcl_SetTimer(timePtr)
Tcl_Time *timePtr; /* Timeout value, may be NULL. */
{
long timeout;
if (!initialized) {
InitNotifier();
}
TclSetAppContext(NULL);
if (notifier.currentTimeout != 0) {
XtRemoveTimeOut(notifier.currentTimeout);
}
if (timePtr) {
timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
notifier.currentTimeout =
XtAppAddTimeOut(notifier.appContext, (unsigned long) timeout,
TimerProc, NULL);
} else {
notifier.currentTimeout = 0;
}
}
/*
*----------------------------------------------------------------------
*
* TimerProc --
*
* This procedure is the XtTimerCallbackProc used to handle
* timeouts.
*
* Results:
* None.
*
* Side effects:
* Processes all queued events.
*
*----------------------------------------------------------------------
*/
static void
TimerProc(data, id)
caddr_t data; /* Not used. */
XtIntervalId *id;
{
if (*id != notifier.currentTimeout) {
return;
}
notifier.currentTimeout = 0;
Tcl_ServiceAll();
}
/*
*----------------------------------------------------------------------
*
* 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -