os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclXtNotify.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/* 
sl@0
     2
 * tclXtNotify.c --
sl@0
     3
 *
sl@0
     4
 *	This file contains the notifier driver implementation for the
sl@0
     5
 *	Xt intrinsics.
sl@0
     6
 *
sl@0
     7
 * Copyright (c) 1997 by Sun Microsystems, Inc.
sl@0
     8
 *
sl@0
     9
 * See the file "license.terms" for information on usage and redistribution
sl@0
    10
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    11
 *
sl@0
    12
 * RCS: @(#) $Id: tclXtNotify.c,v 1.4 1999/07/02 06:05:34 welch Exp $
sl@0
    13
 */
sl@0
    14
sl@0
    15
#include <X11/Intrinsic.h>
sl@0
    16
#include <tclInt.h>
sl@0
    17
sl@0
    18
/*
sl@0
    19
 * This structure is used to keep track of the notifier info for a 
sl@0
    20
 * a registered file.
sl@0
    21
 */
sl@0
    22
sl@0
    23
typedef struct FileHandler {
sl@0
    24
    int fd;
sl@0
    25
    int mask;			/* Mask of desired events: TCL_READABLE, etc. */
sl@0
    26
    int readyMask;		/* Events that have been seen since the
sl@0
    27
				   last time FileHandlerEventProc was called
sl@0
    28
				   for this file. */
sl@0
    29
    XtInputId read;		/* Xt read callback handle. */
sl@0
    30
    XtInputId write;		/* Xt write callback handle. */
sl@0
    31
    XtInputId except;		/* Xt exception callback handle. */
sl@0
    32
    Tcl_FileProc *proc;		/* Procedure to call, in the style of
sl@0
    33
				 * Tcl_CreateFileHandler. */
sl@0
    34
    ClientData clientData;	/* Argument to pass to proc. */
sl@0
    35
    struct FileHandler *nextPtr;/* Next in list of all files we care about. */
sl@0
    36
} FileHandler;
sl@0
    37
sl@0
    38
/*
sl@0
    39
 * The following structure is what is added to the Tcl event queue when
sl@0
    40
 * file handlers are ready to fire.
sl@0
    41
 */
sl@0
    42
sl@0
    43
typedef struct FileHandlerEvent {
sl@0
    44
    Tcl_Event header;		/* Information that is standard for
sl@0
    45
				 * all events. */
sl@0
    46
    int fd;			/* File descriptor that is ready.  Used
sl@0
    47
				 * to find the FileHandler structure for
sl@0
    48
				 * the file (can't point directly to the
sl@0
    49
				 * FileHandler structure because it could
sl@0
    50
				 * go away while the event is queued). */
sl@0
    51
} FileHandlerEvent;
sl@0
    52
sl@0
    53
/*
sl@0
    54
 * The following static structure contains the state information for the
sl@0
    55
 * Xt based implementation of the Tcl notifier.
sl@0
    56
 */
sl@0
    57
sl@0
    58
static struct NotifierState {
sl@0
    59
    XtAppContext appContext;		/* The context used by the Xt
sl@0
    60
                                         * notifier. Can be set with
sl@0
    61
                                         * TclSetAppContext. */
sl@0
    62
    int appContextCreated;		/* Was it created by us? */
sl@0
    63
    XtIntervalId currentTimeout;	/* Handle of current timer. */
sl@0
    64
    FileHandler *firstFileHandlerPtr;	/* Pointer to head of file handler
sl@0
    65
					 * list. */
sl@0
    66
} notifier;
sl@0
    67
sl@0
    68
/*
sl@0
    69
 * The following static indicates whether this module has been initialized.
sl@0
    70
 */
sl@0
    71
sl@0
    72
static int initialized = 0;
sl@0
    73
sl@0
    74
/*
sl@0
    75
 * Static routines defined in this file.
sl@0
    76
 */
sl@0
    77
sl@0
    78
static int		FileHandlerEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
sl@0
    79
			    int flags));
sl@0
    80
static void		FileProc _ANSI_ARGS_((caddr_t clientData,
sl@0
    81
			    int *source, XtInputId *id));
sl@0
    82
void			InitNotifier _ANSI_ARGS_((void));
sl@0
    83
static void		NotifierExitHandler _ANSI_ARGS_((
sl@0
    84
			    ClientData clientData));
sl@0
    85
static void		TimerProc _ANSI_ARGS_((caddr_t clientData,
sl@0
    86
			    XtIntervalId *id));
sl@0
    87
static void		CreateFileHandler _ANSI_ARGS_((int fd, int mask, 
sl@0
    88
				Tcl_FileProc * proc, ClientData clientData));
sl@0
    89
static void		DeleteFileHandler _ANSI_ARGS_((int fd));
sl@0
    90
static void		SetTimer _ANSI_ARGS_((Tcl_Time * timePtr));
sl@0
    91
static int		WaitForEvent _ANSI_ARGS_((Tcl_Time * timePtr));
sl@0
    92
sl@0
    93
/*
sl@0
    94
 * Functions defined in this file for use by users of the Xt Notifier:
sl@0
    95
 */
sl@0
    96
sl@0
    97
EXTERN XtAppContext	TclSetAppContext _ANSI_ARGS_((XtAppContext ctx));
sl@0
    98

sl@0
    99
/*
sl@0
   100
 *----------------------------------------------------------------------
sl@0
   101
 *
sl@0
   102
 * TclSetAppContext --
sl@0
   103
 *
sl@0
   104
 *	Set the notifier application context.
sl@0
   105
 *
sl@0
   106
 * Results:
sl@0
   107
 *	None.
sl@0
   108
 *
sl@0
   109
 * Side effects:
sl@0
   110
 *	Sets the application context used by the notifier. Panics if
sl@0
   111
 *	the context is already set when called.
sl@0
   112
 *
sl@0
   113
 *----------------------------------------------------------------------
sl@0
   114
 */
sl@0
   115
sl@0
   116
XtAppContext
sl@0
   117
TclSetAppContext(appContext)
sl@0
   118
    XtAppContext	appContext;
sl@0
   119
{
sl@0
   120
    if (!initialized) {
sl@0
   121
        InitNotifier();
sl@0
   122
    }
sl@0
   123
sl@0
   124
    /*
sl@0
   125
     * If we already have a context we check whether we were asked to set a
sl@0
   126
     * new context. If so, we panic because we try to prevent switching
sl@0
   127
     * contexts by mistake. Otherwise, we return the one we have.
sl@0
   128
     */
sl@0
   129
    
sl@0
   130
    if (notifier.appContext != NULL) {
sl@0
   131
        if (appContext != NULL) {
sl@0
   132
sl@0
   133
	    /*
sl@0
   134
             * We already have a context. We do not allow switching contexts
sl@0
   135
             * after initialization, so we panic.
sl@0
   136
             */
sl@0
   137
        
sl@0
   138
            panic("TclSetAppContext:  multiple application contexts");
sl@0
   139
sl@0
   140
        }
sl@0
   141
    } else {
sl@0
   142
sl@0
   143
        /*
sl@0
   144
         * If we get here we have not yet gotten a context, so either create
sl@0
   145
         * one or use the one supplied by our caller.
sl@0
   146
         */
sl@0
   147
sl@0
   148
        if (appContext == NULL) {
sl@0
   149
sl@0
   150
	    /*
sl@0
   151
             * We must create a new context and tell our caller what it is, so
sl@0
   152
             * she can use it too.
sl@0
   153
             */
sl@0
   154
    
sl@0
   155
            notifier.appContext = XtCreateApplicationContext();
sl@0
   156
            notifier.appContextCreated = 1;
sl@0
   157
        } else {
sl@0
   158
sl@0
   159
	    /*
sl@0
   160
             * Otherwise we remember the context that our caller gave us
sl@0
   161
             * and use it.
sl@0
   162
             */
sl@0
   163
    
sl@0
   164
            notifier.appContextCreated = 0;
sl@0
   165
            notifier.appContext = appContext;
sl@0
   166
        }
sl@0
   167
    }
sl@0
   168
    
sl@0
   169
    return notifier.appContext;
sl@0
   170
}
sl@0
   171

sl@0
   172
/*
sl@0
   173
 *----------------------------------------------------------------------
sl@0
   174
 *
sl@0
   175
 * InitNotifier --
sl@0
   176
 *
sl@0
   177
 *	Initializes the notifier state.
sl@0
   178
 *
sl@0
   179
 * Results:
sl@0
   180
 *	None.
sl@0
   181
 *
sl@0
   182
 * Side effects:
sl@0
   183
 *	Creates a new exit handler.
sl@0
   184
 *
sl@0
   185
 *----------------------------------------------------------------------
sl@0
   186
 */
sl@0
   187
sl@0
   188
void
sl@0
   189
InitNotifier()
sl@0
   190
{
sl@0
   191
    Tcl_NotifierProcs notifier;
sl@0
   192
    /*
sl@0
   193
     * Only reinitialize if we are not in exit handling. The notifier
sl@0
   194
     * can get reinitialized after its own exit handler has run, because
sl@0
   195
     * of exit handlers for the I/O and timer sub-systems (order dependency).
sl@0
   196
     */
sl@0
   197
sl@0
   198
    if (TclInExit()) {
sl@0
   199
        return;
sl@0
   200
    }
sl@0
   201
sl@0
   202
    notifier.createFileHandlerProc = CreateFileHandler;
sl@0
   203
    notifier.deleteFileHandlerProc = DeleteFileHandler;
sl@0
   204
    notifier.setTimerProc = SetTimer;
sl@0
   205
    notifier.waitForEventProc = WaitForEvent;
sl@0
   206
    Tcl_SetNotifier(&notifier);
sl@0
   207
sl@0
   208
    /*
sl@0
   209
     * DO NOT create the application context yet; doing so would prevent
sl@0
   210
     * external applications from setting it for us to their own ones.
sl@0
   211
     */
sl@0
   212
    
sl@0
   213
    initialized = 1;
sl@0
   214
    memset(&notifier, 0, sizeof(notifier));
sl@0
   215
    Tcl_CreateExitHandler(NotifierExitHandler, NULL);
sl@0
   216
}
sl@0
   217

sl@0
   218
/*
sl@0
   219
 *----------------------------------------------------------------------
sl@0
   220
 *
sl@0
   221
 * NotifierExitHandler --
sl@0
   222
 *
sl@0
   223
 *	This function is called to cleanup the notifier state before
sl@0
   224
 *	Tcl is unloaded.
sl@0
   225
 *
sl@0
   226
 * Results:
sl@0
   227
 *	None.
sl@0
   228
 *
sl@0
   229
 * Side effects:
sl@0
   230
 *	Destroys the notifier window.
sl@0
   231
 *
sl@0
   232
 *----------------------------------------------------------------------
sl@0
   233
 */
sl@0
   234
sl@0
   235
static void
sl@0
   236
NotifierExitHandler(
sl@0
   237
    ClientData clientData)	/* Not used. */
sl@0
   238
{
sl@0
   239
    if (notifier.currentTimeout != 0) {
sl@0
   240
        XtRemoveTimeOut(notifier.currentTimeout);
sl@0
   241
    }
sl@0
   242
    for (; notifier.firstFileHandlerPtr != NULL; ) {
sl@0
   243
        Tcl_DeleteFileHandler(notifier.firstFileHandlerPtr->fd);
sl@0
   244
    }
sl@0
   245
    if (notifier.appContextCreated) {
sl@0
   246
        XtDestroyApplicationContext(notifier.appContext);
sl@0
   247
        notifier.appContextCreated = 0;
sl@0
   248
        notifier.appContext = NULL;
sl@0
   249
    }
sl@0
   250
    initialized = 0;
sl@0
   251
}
sl@0
   252

sl@0
   253
/*
sl@0
   254
 *----------------------------------------------------------------------
sl@0
   255
 *
sl@0
   256
 * SetTimer --
sl@0
   257
 *
sl@0
   258
 *	This procedure sets the current notifier timeout value.
sl@0
   259
 *
sl@0
   260
 * Results:
sl@0
   261
 *	None.
sl@0
   262
 *
sl@0
   263
 * Side effects:
sl@0
   264
 *	Replaces any previous timer.
sl@0
   265
 *
sl@0
   266
 *----------------------------------------------------------------------
sl@0
   267
 */
sl@0
   268
sl@0
   269
static void
sl@0
   270
SetTimer(timePtr)
sl@0
   271
    Tcl_Time *timePtr;		/* Timeout value, may be NULL. */
sl@0
   272
{
sl@0
   273
    long timeout;
sl@0
   274
sl@0
   275
    if (!initialized) {
sl@0
   276
	InitNotifier();
sl@0
   277
    }
sl@0
   278
sl@0
   279
    TclSetAppContext(NULL);
sl@0
   280
    if (notifier.currentTimeout != 0) {
sl@0
   281
	XtRemoveTimeOut(notifier.currentTimeout);
sl@0
   282
    }
sl@0
   283
    if (timePtr) {
sl@0
   284
	timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
sl@0
   285
	notifier.currentTimeout =
sl@0
   286
            XtAppAddTimeOut(notifier.appContext, (unsigned long) timeout,
sl@0
   287
                    TimerProc, NULL);
sl@0
   288
    } else {
sl@0
   289
	notifier.currentTimeout = 0;
sl@0
   290
    }
sl@0
   291
}
sl@0
   292

sl@0
   293
/*
sl@0
   294
 *----------------------------------------------------------------------
sl@0
   295
 *
sl@0
   296
 * TimerProc --
sl@0
   297
 *
sl@0
   298
 *	This procedure is the XtTimerCallbackProc used to handle
sl@0
   299
 *	timeouts.
sl@0
   300
 *
sl@0
   301
 * Results:
sl@0
   302
 *	None.
sl@0
   303
 *
sl@0
   304
 * Side effects:
sl@0
   305
 *      Processes all queued events.
sl@0
   306
 *
sl@0
   307
 *----------------------------------------------------------------------
sl@0
   308
 */
sl@0
   309
sl@0
   310
static void
sl@0
   311
TimerProc(data, id)
sl@0
   312
    caddr_t data;		/* Not used. */
sl@0
   313
    XtIntervalId *id;
sl@0
   314
{
sl@0
   315
    if (*id != notifier.currentTimeout) {
sl@0
   316
	return;
sl@0
   317
    }
sl@0
   318
    notifier.currentTimeout = 0;
sl@0
   319
sl@0
   320
    Tcl_ServiceAll();
sl@0
   321
}
sl@0
   322

sl@0
   323
/*
sl@0
   324
 *----------------------------------------------------------------------
sl@0
   325
 *
sl@0
   326
 * CreateFileHandler --
sl@0
   327
 *
sl@0
   328
 *	This procedure registers a file handler with the Xt notifier.
sl@0
   329
 *
sl@0
   330
 * Results:
sl@0
   331
 *	None.
sl@0
   332
 *
sl@0
   333
 * Side effects:
sl@0
   334
 *	Creates a new file handler structure and registers one or more
sl@0
   335
 *	input procedures with Xt.
sl@0
   336
 *
sl@0
   337
 *----------------------------------------------------------------------
sl@0
   338
 */
sl@0
   339
sl@0
   340
static void
sl@0
   341
CreateFileHandler(fd, mask, proc, clientData)
sl@0
   342
    int fd;			/* Handle of stream to watch. */
sl@0
   343
    int mask;			/* OR'ed combination of TCL_READABLE,
sl@0
   344
				 * TCL_WRITABLE, and TCL_EXCEPTION:
sl@0
   345
				 * indicates conditions under which
sl@0
   346
				 * proc should be called. */
sl@0
   347
    Tcl_FileProc *proc;		/* Procedure to call for each
sl@0
   348
				 * selected event. */
sl@0
   349
    ClientData clientData;	/* Arbitrary data to pass to proc. */
sl@0
   350
{
sl@0
   351
    FileHandler *filePtr;
sl@0
   352
sl@0
   353
    if (!initialized) {
sl@0
   354
	InitNotifier();
sl@0
   355
    }
sl@0
   356
sl@0
   357
    TclSetAppContext(NULL);
sl@0
   358
sl@0
   359
    for (filePtr = notifier.firstFileHandlerPtr; filePtr != NULL;
sl@0
   360
	    filePtr = filePtr->nextPtr) {
sl@0
   361
	if (filePtr->fd == fd) {
sl@0
   362
	    break;
sl@0
   363
	}
sl@0
   364
    }
sl@0
   365
    if (filePtr == NULL) {
sl@0
   366
	filePtr = (FileHandler*) ckalloc(sizeof(FileHandler));
sl@0
   367
	filePtr->fd = fd;
sl@0
   368
	filePtr->read = 0;
sl@0
   369
	filePtr->write = 0;
sl@0
   370
	filePtr->except = 0;
sl@0
   371
	filePtr->readyMask = 0;
sl@0
   372
	filePtr->mask = 0;
sl@0
   373
	filePtr->nextPtr = notifier.firstFileHandlerPtr;
sl@0
   374
	notifier.firstFileHandlerPtr = filePtr;
sl@0
   375
    }
sl@0
   376
    filePtr->proc = proc;
sl@0
   377
    filePtr->clientData = clientData;
sl@0
   378
sl@0
   379
    /*
sl@0
   380
     * Register the file with the Xt notifier, if it hasn't been done yet.
sl@0
   381
     */
sl@0
   382
sl@0
   383
    if (mask & TCL_READABLE) {
sl@0
   384
	if (!(filePtr->mask & TCL_READABLE)) {
sl@0
   385
	    filePtr->read =
sl@0
   386
                XtAppAddInput(notifier.appContext, fd, XtInputReadMask,
sl@0
   387
                        FileProc, filePtr);
sl@0
   388
	}
sl@0
   389
    } else {
sl@0
   390
	if (filePtr->mask & TCL_READABLE) {
sl@0
   391
	    XtRemoveInput(filePtr->read);
sl@0
   392
	}
sl@0
   393
    }
sl@0
   394
    if (mask & TCL_WRITABLE) {
sl@0
   395
	if (!(filePtr->mask & TCL_WRITABLE)) {
sl@0
   396
	    filePtr->write =
sl@0
   397
                XtAppAddInput(notifier.appContext, fd, XtInputWriteMask,
sl@0
   398
                        FileProc, filePtr);
sl@0
   399
	}
sl@0
   400
    } else {
sl@0
   401
	if (filePtr->mask & TCL_WRITABLE) {
sl@0
   402
	    XtRemoveInput(filePtr->write);
sl@0
   403
	}
sl@0
   404
    }
sl@0
   405
    if (mask & TCL_EXCEPTION) {
sl@0
   406
	if (!(filePtr->mask & TCL_EXCEPTION)) {
sl@0
   407
	    filePtr->except =
sl@0
   408
                XtAppAddInput(notifier.appContext, fd, XtInputExceptMask,
sl@0
   409
                        FileProc, filePtr);
sl@0
   410
	}
sl@0
   411
    } else {
sl@0
   412
	if (filePtr->mask & TCL_EXCEPTION) {
sl@0
   413
	    XtRemoveInput(filePtr->except);
sl@0
   414
	}
sl@0
   415
    }
sl@0
   416
    filePtr->mask = mask;
sl@0
   417
}
sl@0
   418

sl@0
   419
/*
sl@0
   420
 *----------------------------------------------------------------------
sl@0
   421
 *
sl@0
   422
 * DeleteFileHandler --
sl@0
   423
 *
sl@0
   424
 *	Cancel a previously-arranged callback arrangement for
sl@0
   425
 *	a file.
sl@0
   426
 *
sl@0
   427
 * Results:
sl@0
   428
 *	None.
sl@0
   429
 *
sl@0
   430
 * Side effects:
sl@0
   431
 *	If a callback was previously registered on file, remove it.
sl@0
   432
 *
sl@0
   433
 *----------------------------------------------------------------------
sl@0
   434
 */
sl@0
   435
sl@0
   436
static void
sl@0
   437
DeleteFileHandler(fd)
sl@0
   438
    int fd;			/* Stream id for which to remove
sl@0
   439
				 * callback procedure. */
sl@0
   440
{
sl@0
   441
    FileHandler *filePtr, *prevPtr;
sl@0
   442
sl@0
   443
    if (!initialized) {
sl@0
   444
	InitNotifier();
sl@0
   445
    }
sl@0
   446
sl@0
   447
    TclSetAppContext(NULL);
sl@0
   448
sl@0
   449
    /*
sl@0
   450
     * Find the entry for the given file (and return if there
sl@0
   451
     * isn't one).
sl@0
   452
     */
sl@0
   453
sl@0
   454
    for (prevPtr = NULL, filePtr = notifier.firstFileHandlerPtr; ;
sl@0
   455
	    prevPtr = filePtr, filePtr = filePtr->nextPtr) {
sl@0
   456
	if (filePtr == NULL) {
sl@0
   457
	    return;
sl@0
   458
	}
sl@0
   459
	if (filePtr->fd == fd) {
sl@0
   460
	    break;
sl@0
   461
	}
sl@0
   462
    }
sl@0
   463
sl@0
   464
    /*
sl@0
   465
     * Clean up information in the callback record.
sl@0
   466
     */
sl@0
   467
sl@0
   468
    if (prevPtr == NULL) {
sl@0
   469
	notifier.firstFileHandlerPtr = filePtr->nextPtr;
sl@0
   470
    } else {
sl@0
   471
	prevPtr->nextPtr = filePtr->nextPtr;
sl@0
   472
    }
sl@0
   473
    if (filePtr->mask & TCL_READABLE) {
sl@0
   474
	XtRemoveInput(filePtr->read);
sl@0
   475
    }
sl@0
   476
    if (filePtr->mask & TCL_WRITABLE) {
sl@0
   477
	XtRemoveInput(filePtr->write);
sl@0
   478
    }
sl@0
   479
    if (filePtr->mask & TCL_EXCEPTION) {
sl@0
   480
	XtRemoveInput(filePtr->except);
sl@0
   481
    }
sl@0
   482
    ckfree((char *) filePtr);
sl@0
   483
}
sl@0
   484

sl@0
   485
/*
sl@0
   486
 *----------------------------------------------------------------------
sl@0
   487
 *
sl@0
   488
 * FileProc --
sl@0
   489
 *
sl@0
   490
 *	These procedures are called by Xt when a file becomes readable,
sl@0
   491
 *	writable, or has an exception.
sl@0
   492
 *
sl@0
   493
 * Results:
sl@0
   494
 *	None.
sl@0
   495
 *
sl@0
   496
 * Side effects:
sl@0
   497
 *	Makes an entry on the Tcl event queue if the event is
sl@0
   498
 *	interesting.
sl@0
   499
 *
sl@0
   500
 *----------------------------------------------------------------------
sl@0
   501
 */
sl@0
   502
sl@0
   503
static void
sl@0
   504
FileProc(clientData, fd, id)
sl@0
   505
    caddr_t clientData;
sl@0
   506
    int *fd;
sl@0
   507
    XtInputId *id;
sl@0
   508
{
sl@0
   509
    FileHandler *filePtr = (FileHandler *)clientData;
sl@0
   510
    FileHandlerEvent *fileEvPtr;
sl@0
   511
    int mask = 0;
sl@0
   512
sl@0
   513
    /*
sl@0
   514
     * Determine which event happened.
sl@0
   515
     */
sl@0
   516
sl@0
   517
    if (*id == filePtr->read) {
sl@0
   518
	mask = TCL_READABLE;
sl@0
   519
    } else if (*id == filePtr->write) {
sl@0
   520
	mask = TCL_WRITABLE;
sl@0
   521
    } else if (*id == filePtr->except) {
sl@0
   522
	mask = TCL_EXCEPTION;
sl@0
   523
    }
sl@0
   524
sl@0
   525
    /*
sl@0
   526
     * Ignore unwanted or duplicate events.
sl@0
   527
     */
sl@0
   528
sl@0
   529
    if (!(filePtr->mask & mask) || (filePtr->readyMask & mask)) {
sl@0
   530
	return;
sl@0
   531
    }
sl@0
   532
    
sl@0
   533
    /*
sl@0
   534
     * This is an interesting event, so put it onto the event queue.
sl@0
   535
     */
sl@0
   536
sl@0
   537
    filePtr->readyMask |= mask;
sl@0
   538
    fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent));
sl@0
   539
    fileEvPtr->header.proc = FileHandlerEventProc;
sl@0
   540
    fileEvPtr->fd = filePtr->fd;
sl@0
   541
    Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
sl@0
   542
sl@0
   543
    /*
sl@0
   544
     * Process events on the Tcl event queue before returning to Xt.
sl@0
   545
     */
sl@0
   546
sl@0
   547
    Tcl_ServiceAll();
sl@0
   548
}
sl@0
   549

sl@0
   550
/*
sl@0
   551
 *----------------------------------------------------------------------
sl@0
   552
 *
sl@0
   553
 * FileHandlerEventProc --
sl@0
   554
 *
sl@0
   555
 *	This procedure is called by Tcl_ServiceEvent when a file event
sl@0
   556
 *	reaches the front of the event queue.  This procedure is
sl@0
   557
 *	responsible for actually handling the event by invoking the
sl@0
   558
 *	callback for the file handler.
sl@0
   559
 *
sl@0
   560
 * Results:
sl@0
   561
 *	Returns 1 if the event was handled, meaning it should be removed
sl@0
   562
 *	from the queue.  Returns 0 if the event was not handled, meaning
sl@0
   563
 *	it should stay on the queue.  The only time the event isn't
sl@0
   564
 *	handled is if the TCL_FILE_EVENTS flag bit isn't set.
sl@0
   565
 *
sl@0
   566
 * Side effects:
sl@0
   567
 *	Whatever the file handler's callback procedure does.
sl@0
   568
 *
sl@0
   569
 *----------------------------------------------------------------------
sl@0
   570
 */
sl@0
   571
sl@0
   572
static int
sl@0
   573
FileHandlerEventProc(evPtr, flags)
sl@0
   574
    Tcl_Event *evPtr;		/* Event to service. */
sl@0
   575
    int flags;			/* Flags that indicate what events to
sl@0
   576
				 * handle, such as TCL_FILE_EVENTS. */
sl@0
   577
{
sl@0
   578
    FileHandler *filePtr;
sl@0
   579
    FileHandlerEvent *fileEvPtr = (FileHandlerEvent *) evPtr;
sl@0
   580
    int mask;
sl@0
   581
sl@0
   582
    if (!(flags & TCL_FILE_EVENTS)) {
sl@0
   583
	return 0;
sl@0
   584
    }
sl@0
   585
sl@0
   586
    /*
sl@0
   587
     * Search through the file handlers to find the one whose handle matches
sl@0
   588
     * the event.  We do this rather than keeping a pointer to the file
sl@0
   589
     * handler directly in the event, so that the handler can be deleted
sl@0
   590
     * while the event is queued without leaving a dangling pointer.
sl@0
   591
     */
sl@0
   592
sl@0
   593
    for (filePtr = notifier.firstFileHandlerPtr; filePtr != NULL;
sl@0
   594
	    filePtr = filePtr->nextPtr) {
sl@0
   595
	if (filePtr->fd != fileEvPtr->fd) {
sl@0
   596
	    continue;
sl@0
   597
	}
sl@0
   598
sl@0
   599
	/*
sl@0
   600
	 * The code is tricky for two reasons:
sl@0
   601
	 * 1. The file handler's desired events could have changed
sl@0
   602
	 *    since the time when the event was queued, so AND the
sl@0
   603
	 *    ready mask with the desired mask.
sl@0
   604
	 * 2. The file could have been closed and re-opened since
sl@0
   605
	 *    the time when the event was queued.  This is why the
sl@0
   606
	 *    ready mask is stored in the file handler rather than
sl@0
   607
	 *    the queued event:  it will be zeroed when a new
sl@0
   608
	 *    file handler is created for the newly opened file.
sl@0
   609
	 */
sl@0
   610
sl@0
   611
	mask = filePtr->readyMask & filePtr->mask;
sl@0
   612
	filePtr->readyMask = 0;
sl@0
   613
	if (mask != 0) {
sl@0
   614
	    (*filePtr->proc)(filePtr->clientData, mask);
sl@0
   615
	}
sl@0
   616
	break;
sl@0
   617
    }
sl@0
   618
    return 1;
sl@0
   619
}
sl@0
   620

sl@0
   621
/*
sl@0
   622
 *----------------------------------------------------------------------
sl@0
   623
 *
sl@0
   624
 * WaitForEvent --
sl@0
   625
 *
sl@0
   626
 *	This function is called by Tcl_DoOneEvent to wait for new
sl@0
   627
 *	events on the message queue.  If the block time is 0, then
sl@0
   628
 *	Tcl_WaitForEvent just polls without blocking.
sl@0
   629
 *
sl@0
   630
 * Results:
sl@0
   631
 *	Returns 1 if an event was found, else 0.  This ensures that
sl@0
   632
 *	Tcl_DoOneEvent will return 1, even if the event is handled
sl@0
   633
 *	by non-Tcl code.
sl@0
   634
 *
sl@0
   635
 * Side effects:
sl@0
   636
 *	Queues file events that are detected by the select.
sl@0
   637
 *
sl@0
   638
 *----------------------------------------------------------------------
sl@0
   639
 */
sl@0
   640
sl@0
   641
static int
sl@0
   642
WaitForEvent(
sl@0
   643
    Tcl_Time *timePtr)		/* Maximum block time, or NULL. */
sl@0
   644
{
sl@0
   645
    int timeout;
sl@0
   646
sl@0
   647
    if (!initialized) {
sl@0
   648
	InitNotifier();
sl@0
   649
    }
sl@0
   650
sl@0
   651
    TclSetAppContext(NULL);
sl@0
   652
sl@0
   653
    if (timePtr) {
sl@0
   654
        timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
sl@0
   655
        if (timeout == 0) {
sl@0
   656
            if (XtAppPending(notifier.appContext)) {
sl@0
   657
                goto process;
sl@0
   658
            } else {
sl@0
   659
                return 0;
sl@0
   660
            }
sl@0
   661
        } else {
sl@0
   662
            Tcl_SetTimer(timePtr);
sl@0
   663
        }
sl@0
   664
    }
sl@0
   665
process:
sl@0
   666
    XtAppProcessEvent(notifier.appContext, XtIMAll);
sl@0
   667
    return 1;
sl@0
   668
}