OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tcl/] [generic/] [tclNotify.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tclNotify.c --
3
 *
4
 *      This file implements the generic portion of the Tcl notifier.
5
 *      The notifier is lowest-level part of the event system.  It
6
 *      manages an event queue that holds Tcl_Event structures.  The
7
 *      platform specific portion of the notifier is defined in the
8
 *      tcl*Notify.c files in each platform directory.
9
 *
10
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
11
 * Copyright (c) 1998 by Scriptics Corporation.
12
 *
13
 * See the file "license.terms" for information on usage and redistribution
14
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15
 *
16
 * RCS: @(#) $Id: tclNotify.c,v 1.1.1.1 2002-01-16 10:25:28 markom Exp $
17
 */
18
 
19
#include "tclInt.h"
20
#include "tclPort.h"
21
 
22
/*
23
 * The following static indicates whether this module has been initialized.
24
 */
25
 
26
static int initialized = 0;
27
 
28
/*
29
 * For each event source (created with Tcl_CreateEventSource) there
30
 * is a structure of the following type:
31
 */
32
 
33
typedef struct EventSource {
34
    Tcl_EventSetupProc *setupProc;
35
    Tcl_EventCheckProc *checkProc;
36
    ClientData clientData;
37
    struct EventSource *nextPtr;
38
} EventSource;
39
 
40
/*
41
 * The following structure keeps track of the state of the notifier.
42
 * The first three elements keep track of the event queue.  In addition to
43
 * the first (next to be serviced) and last events in the queue, we keep
44
 * track of a "marker" event.  This provides a simple priority mechanism
45
 * whereby events can be inserted at the front of the queue but behind all
46
 * other high-priority events already in the queue (this is used for things
47
 * like a sequence of Enter and Leave events generated during a grab in
48
 * Tk).
49
 */
50
 
51
static struct {
52
    Tcl_Event *firstEventPtr;   /* First pending event, or NULL if none. */
53
    Tcl_Event *lastEventPtr;    /* Last pending event, or NULL if none. */
54
    Tcl_Event *markerEventPtr;  /* Last high-priority event in queue, or
55
                                 * NULL if none. */
56
    int serviceMode;            /* One of TCL_SERVICE_NONE or
57
                                 * TCL_SERVICE_ALL. */
58
    int blockTimeSet;           /* 0 means there is no maximum block
59
                                 * time:  block forever. */
60
    Tcl_Time blockTime;         /* If blockTimeSet is 1, gives the
61
                                 * maximum elapsed time for the next block. */
62
    int inTraversal;            /* 1 if Tcl_SetMaxBlockTime is being
63
                                 * called during an event source traversal. */
64
    EventSource *firstEventSourcePtr;
65
                                /* Pointer to first event source in
66
                                 * global list of event sources. */
67
} notifier;
68
 
69
/*
70
 * Declarations for functions used in this file.
71
 */
72
 
73
static void     InitNotifier _ANSI_ARGS_((void));
74
static void     NotifierExitHandler _ANSI_ARGS_((ClientData clientData));
75
 
76
 
77
/*
78
 *----------------------------------------------------------------------
79
 *
80
 * InitNotifier --
81
 *
82
 *      This routine is called to initialize the notifier module.
83
 *
84
 * Results:
85
 *      None.
86
 *
87
 * Side effects:
88
 *      Creates an exit handler and initializes static data.
89
 *
90
 *----------------------------------------------------------------------
91
 */
92
 
93
static void
94
InitNotifier()
95
{
96
    initialized = 1;
97
    memset(&notifier, 0, sizeof(notifier));
98
    notifier.serviceMode = TCL_SERVICE_NONE;
99
    Tcl_CreateExitHandler(NotifierExitHandler, NULL);
100
}
101
 
102
/*
103
 *----------------------------------------------------------------------
104
 *
105
 * NotifierExitHandler --
106
 *
107
 *      This routine is called during Tcl finalization.
108
 *
109
 * Results:
110
 *      None.
111
 *
112
 * Side effects:
113
 *      Clears the notifier intialization flag.
114
 *
115
 *----------------------------------------------------------------------
116
 */
117
 
118
static void
119
NotifierExitHandler(clientData)
120
    ClientData clientData;  /* Not used. */
121
{
122
    initialized = 0;
123
}
124
 
125
/*
126
 *----------------------------------------------------------------------
127
 *
128
 * Tcl_CreateEventSource --
129
 *
130
 *      This procedure is invoked to create a new source of events.
131
 *      The source is identified by a procedure that gets invoked
132
 *      during Tcl_DoOneEvent to check for events on that source
133
 *      and queue them.
134
 *
135
 *
136
 * Results:
137
 *      None.
138
 *
139
 * Side effects:
140
 *      SetupProc and checkProc will be invoked each time that Tcl_DoOneEvent
141
 *      runs out of things to do.  SetupProc will be invoked before
142
 *      Tcl_DoOneEvent calls select or whatever else it uses to wait
143
 *      for events.  SetupProc typically calls functions like Tcl_WatchFile
144
 *      or Tcl_SetMaxBlockTime to indicate what to wait for.
145
 *
146
 *      CheckProc is called after select or whatever operation was actually
147
 *      used to wait.  It figures out whether anything interesting actually
148
 *      happened (e.g. by calling Tcl_FileReady), and then calls
149
 *      Tcl_QueueEvent to queue any events that are ready.
150
 *
151
 *      Each of these procedures is passed two arguments, e.g.
152
 *              (*checkProc)(ClientData clientData, int flags));
153
 *      ClientData is the same as the clientData argument here, and flags
154
 *      is a combination of things like TCL_FILE_EVENTS that indicates
155
 *      what events are of interest:  setupProc and checkProc use flags
156
 *      to figure out whether their events are relevant or not.
157
 *
158
 *----------------------------------------------------------------------
159
 */
160
 
161
void
162
Tcl_CreateEventSource(setupProc, checkProc, clientData)
163
    Tcl_EventSetupProc *setupProc;      /* Procedure to invoke to figure out
164
                                         * what to wait for. */
165
    Tcl_EventCheckProc *checkProc;      /* Procedure to call after waiting
166
                                         * to see what happened. */
167
    ClientData clientData;              /* One-word argument to pass to
168
                                         * setupProc and checkProc. */
169
{
170
    EventSource *sourcePtr;
171
 
172
    if (!initialized) {
173
        InitNotifier();
174
    }
175
 
176
    sourcePtr = (EventSource *) ckalloc(sizeof(EventSource));
177
    sourcePtr->setupProc = setupProc;
178
    sourcePtr->checkProc = checkProc;
179
    sourcePtr->clientData = clientData;
180
    sourcePtr->nextPtr = notifier.firstEventSourcePtr;
181
    notifier.firstEventSourcePtr = sourcePtr;
182
}
183
 
184
/*
185
 *----------------------------------------------------------------------
186
 *
187
 * Tcl_DeleteEventSource --
188
 *
189
 *      This procedure is invoked to delete the source of events
190
 *      given by proc and clientData.
191
 *
192
 * Results:
193
 *      None.
194
 *
195
 * Side effects:
196
 *      The given event source is cancelled, so its procedure will
197
 *      never again be called.  If no such source exists, nothing
198
 *      happens.
199
 *
200
 *----------------------------------------------------------------------
201
 */
202
 
203
void
204
Tcl_DeleteEventSource(setupProc, checkProc, clientData)
205
    Tcl_EventSetupProc *setupProc;      /* Procedure to invoke to figure out
206
                                         * what to wait for. */
207
    Tcl_EventCheckProc *checkProc;      /* Procedure to call after waiting
208
                                         * to see what happened. */
209
    ClientData clientData;              /* One-word argument to pass to
210
                                         * setupProc and checkProc. */
211
{
212
    EventSource *sourcePtr, *prevPtr;
213
 
214
    for (sourcePtr = notifier.firstEventSourcePtr, prevPtr = NULL;
215
            sourcePtr != NULL;
216
            prevPtr = sourcePtr, sourcePtr = sourcePtr->nextPtr) {
217
        if ((sourcePtr->setupProc != setupProc)
218
                || (sourcePtr->checkProc != checkProc)
219
                || (sourcePtr->clientData != clientData)) {
220
            continue;
221
        }
222
        if (prevPtr == NULL) {
223
            notifier.firstEventSourcePtr = sourcePtr->nextPtr;
224
        } else {
225
            prevPtr->nextPtr = sourcePtr->nextPtr;
226
        }
227
        ckfree((char *) sourcePtr);
228
        return;
229
    }
230
}
231
 
232
/*
233
 *----------------------------------------------------------------------
234
 *
235
 * Tcl_QueueEvent --
236
 *
237
 *      Insert an event into the Tk event queue at one of three
238
 *      positions: the head, the tail, or before a floating marker.
239
 *      Events inserted before the marker will be processed in
240
 *      first-in-first-out order, but before any events inserted at
241
 *      the tail of the queue.  Events inserted at the head of the
242
 *      queue will be processed in last-in-first-out order.
243
 *
244
 * Results:
245
 *      None.
246
 *
247
 * Side effects:
248
 *      None.
249
 *
250
 *----------------------------------------------------------------------
251
 */
252
 
253
void
254
Tcl_QueueEvent(evPtr, position)
255
    Tcl_Event* evPtr;           /* Event to add to queue.  The storage
256
                                 * space must have been allocated the caller
257
                                 * with malloc (ckalloc), and it becomes
258
                                 * the property of the event queue.  It
259
                                 * will be freed after the event has been
260
                                 * handled. */
261
    Tcl_QueuePosition position; /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
262
                                 * TCL_QUEUE_MARK. */
263
{
264
    if (!initialized) {
265
        InitNotifier();
266
    }
267
 
268
    if (position == TCL_QUEUE_TAIL) {
269
        /*
270
         * Append the event on the end of the queue.
271
         */
272
 
273
        evPtr->nextPtr = NULL;
274
        if (notifier.firstEventPtr == NULL) {
275
            notifier.firstEventPtr = evPtr;
276
        } else {
277
            notifier.lastEventPtr->nextPtr = evPtr;
278
        }
279
        notifier.lastEventPtr = evPtr;
280
    } else if (position == TCL_QUEUE_HEAD) {
281
        /*
282
         * Push the event on the head of the queue.
283
         */
284
 
285
        evPtr->nextPtr = notifier.firstEventPtr;
286
        if (notifier.firstEventPtr == NULL) {
287
            notifier.lastEventPtr = evPtr;
288
        }
289
        notifier.firstEventPtr = evPtr;
290
    } else if (position == TCL_QUEUE_MARK) {
291
        /*
292
         * Insert the event after the current marker event and advance
293
         * the marker to the new event.
294
         */
295
 
296
        if (notifier.markerEventPtr == NULL) {
297
            evPtr->nextPtr = notifier.firstEventPtr;
298
            notifier.firstEventPtr = evPtr;
299
        } else {
300
            evPtr->nextPtr = notifier.markerEventPtr->nextPtr;
301
            notifier.markerEventPtr->nextPtr = evPtr;
302
        }
303
        notifier.markerEventPtr = evPtr;
304
        if (evPtr->nextPtr == NULL) {
305
            notifier.lastEventPtr = evPtr;
306
        }
307
    }
308
}
309
 
310
/*
311
 *----------------------------------------------------------------------
312
 *
313
 * Tcl_DeleteEvents --
314
 *
315
 *      Calls a procedure for each event in the queue and deletes those
316
 *      for which the procedure returns 1. Events for which the
317
 *      procedure returns 0 are left in the queue.
318
 *
319
 * Results:
320
 *      None.
321
 *
322
 * Side effects:
323
 *      Potentially removes one or more events from the event queue.
324
 *
325
 *----------------------------------------------------------------------
326
 */
327
 
328
void
329
Tcl_DeleteEvents(proc, clientData)
330
    Tcl_EventDeleteProc *proc;          /* The procedure to call. */
331
    ClientData clientData;              /* type-specific data. */
332
{
333
    Tcl_Event *evPtr, *prevPtr, *hold;
334
 
335
    if (!initialized) {
336
        InitNotifier();
337
    }
338
 
339
    for (prevPtr = (Tcl_Event *) NULL, evPtr = notifier.firstEventPtr;
340
             evPtr != (Tcl_Event *) NULL;
341
             ) {
342
        if ((*proc) (evPtr, clientData) == 1) {
343
            if (notifier.firstEventPtr == evPtr) {
344
                notifier.firstEventPtr = evPtr->nextPtr;
345
                if (evPtr->nextPtr == NULL) {
346
                    notifier.lastEventPtr = prevPtr;
347
                }
348
                if (notifier.markerEventPtr == evPtr) {
349
                    notifier.markerEventPtr = prevPtr;
350
                }
351
            } else {
352
                prevPtr->nextPtr = evPtr->nextPtr;
353
            }
354
            hold = evPtr;
355
            evPtr = evPtr->nextPtr;
356
            ckfree((char *) hold);
357
        } else {
358
            prevPtr = evPtr;
359
            evPtr = evPtr->nextPtr;
360
        }
361
    }
362
}
363
 
364
/*
365
 *----------------------------------------------------------------------
366
 *
367
 * Tcl_ServiceEvent --
368
 *
369
 *      Process one event from the event queue, or invoke an
370
 *      asynchronous event handler.
371
 *
372
 * Results:
373
 *      The return value is 1 if the procedure actually found an event
374
 *      to process.  If no processing occurred, then 0 is returned.
375
 *
376
 * Side effects:
377
 *      Invokes all of the event handlers for the highest priority
378
 *      event in the event queue.  May collapse some events into a
379
 *      single event or discard stale events.
380
 *
381
 *----------------------------------------------------------------------
382
 */
383
 
384
int
385
Tcl_ServiceEvent(flags)
386
    int flags;                  /* Indicates what events should be processed.
387
                                 * May be any combination of TCL_WINDOW_EVENTS
388
                                 * TCL_FILE_EVENTS, TCL_TIMER_EVENTS, or other
389
                                 * flags defined elsewhere.  Events not
390
                                 * matching this will be skipped for processing
391
                                 * later. */
392
{
393
    Tcl_Event *evPtr, *prevPtr;
394
    Tcl_EventProc *proc;
395
 
396
    if (!initialized) {
397
        InitNotifier();
398
    }
399
 
400
    /*
401
     * Asynchronous event handlers are considered to be the highest
402
     * priority events, and so must be invoked before we process events
403
     * on the event queue.
404
     */
405
 
406
    if (Tcl_AsyncReady()) {
407
        (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
408
        return 1;
409
    }
410
 
411
    /*
412
     * No event flags is equivalent to TCL_ALL_EVENTS.
413
     */
414
 
415
    if ((flags & TCL_ALL_EVENTS) == 0) {
416
        flags |= TCL_ALL_EVENTS;
417
    }
418
 
419
    /*
420
     * Loop through all the events in the queue until we find one
421
     * that can actually be handled.
422
     */
423
 
424
    for (evPtr = notifier.firstEventPtr; evPtr != NULL;
425
         evPtr = evPtr->nextPtr) {
426
        /*
427
         * Call the handler for the event.  If it actually handles the
428
         * event then free the storage for the event.  There are two
429
         * tricky things here, but stemming from the fact that the event
430
         * code may be re-entered while servicing the event:
431
         *
432
         * 1. Set the "proc" field to NULL.  This is a signal to ourselves
433
         *    that we shouldn't reexecute the handler if the event loop
434
         *    is re-entered.
435
         * 2. When freeing the event, must search the queue again from the
436
         *    front to find it.  This is because the event queue could
437
         *    change almost arbitrarily while handling the event, so we
438
         *    can't depend on pointers found now still being valid when
439
         *    the handler returns.
440
         */
441
 
442
        proc = evPtr->proc;
443
        evPtr->proc = NULL;
444
        if ((proc != NULL) && (*proc)(evPtr, flags)) {
445
            if (notifier.firstEventPtr == evPtr) {
446
                notifier.firstEventPtr = evPtr->nextPtr;
447
                if (evPtr->nextPtr == NULL) {
448
                    notifier.lastEventPtr = NULL;
449
                }
450
                if (notifier.markerEventPtr == evPtr) {
451
                    notifier.markerEventPtr = NULL;
452
                }
453
            } else {
454
                for (prevPtr = notifier.firstEventPtr;
455
                     prevPtr->nextPtr != evPtr; prevPtr = prevPtr->nextPtr) {
456
                    /* Empty loop body. */
457
                }
458
                prevPtr->nextPtr = evPtr->nextPtr;
459
                if (evPtr->nextPtr == NULL) {
460
                    notifier.lastEventPtr = prevPtr;
461
                }
462
                if (notifier.markerEventPtr == evPtr) {
463
                    notifier.markerEventPtr = prevPtr;
464
                }
465
            }
466
            ckfree((char *) evPtr);
467
            return 1;
468
        } else {
469
            /*
470
             * The event wasn't actually handled, so we have to restore
471
             * the proc field to allow the event to be attempted again.
472
             */
473
 
474
            evPtr->proc = proc;
475
        }
476
 
477
        /*
478
         * The handler for this event asked to defer it.  Just go on to
479
         * the next event.
480
         */
481
 
482
        continue;
483
    }
484
    return 0;
485
}
486
 
487
/*
488
 *----------------------------------------------------------------------
489
 *
490
 * Tcl_GetServiceMode --
491
 *
492
 *      This routine returns the current service mode of the notifier.
493
 *
494
 * Results:
495
 *      Returns either TCL_SERVICE_ALL or TCL_SERVICE_NONE.
496
 *
497
 * Side effects:
498
 *      None.
499
 *
500
 *----------------------------------------------------------------------
501
 */
502
 
503
int
504
Tcl_GetServiceMode()
505
{
506
    if (!initialized) {
507
        InitNotifier();
508
    }
509
 
510
    return notifier.serviceMode;
511
}
512
 
513
/*
514
 *----------------------------------------------------------------------
515
 *
516
 * Tcl_SetServiceMode --
517
 *
518
 *      This routine sets the current service mode of the notifier.
519
 *
520
 * Results:
521
 *      Returns the previous service mode.
522
 *
523
 * Side effects:
524
 *      None.
525
 *
526
 *----------------------------------------------------------------------
527
 */
528
 
529
int
530
Tcl_SetServiceMode(mode)
531
    int mode;                   /* New service mode: TCL_SERVICE_ALL or
532
                                 * TCL_SERVICE_NONE */
533
{
534
    int oldMode;
535
 
536
    if (!initialized) {
537
        InitNotifier();
538
    }
539
 
540
    oldMode = notifier.serviceMode;
541
    notifier.serviceMode = mode;
542
    return oldMode;
543
}
544
 
545
/*
546
 *----------------------------------------------------------------------
547
 *
548
 * Tcl_SetMaxBlockTime --
549
 *
550
 *      This procedure is invoked by event sources to tell the notifier
551
 *      how long it may block the next time it blocks.  The timePtr
552
 *      argument gives a maximum time;  the actual time may be less if
553
 *      some other event source requested a smaller time.
554
 *
555
 * Results:
556
 *      None.
557
 *
558
 * Side effects:
559
 *      May reduce the length of the next sleep in the notifier.
560
 *
561
 *----------------------------------------------------------------------
562
 */
563
 
564
void
565
Tcl_SetMaxBlockTime(timePtr)
566
    Tcl_Time *timePtr;          /* Specifies a maximum elapsed time for
567
                                 * the next blocking operation in the
568
                                 * event notifier. */
569
{
570
    if (!initialized) {
571
        InitNotifier();
572
    }
573
 
574
    if (!notifier.blockTimeSet || (timePtr->sec < notifier.blockTime.sec)
575
            || ((timePtr->sec == notifier.blockTime.sec)
576
            && (timePtr->usec < notifier.blockTime.usec))) {
577
        notifier.blockTime = *timePtr;
578
        notifier.blockTimeSet = 1;
579
    }
580
 
581
    /*
582
     * If we are called outside an event source traversal, set the
583
     * timeout immediately.
584
     */
585
 
586
    if (!notifier.inTraversal) {
587
        if (notifier.blockTimeSet) {
588
            Tcl_SetTimer(&notifier.blockTime);
589
        } else {
590
            Tcl_SetTimer(NULL);
591
        }
592
    }
593
}
594
 
595
/*
596
 *----------------------------------------------------------------------
597
 *
598
 * Tcl_DoOneEvent --
599
 *
600
 *      Process a single event of some sort.  If there's no work to
601
 *      do, wait for an event to occur, then process it.
602
 *
603
 * Results:
604
 *      The return value is 1 if the procedure actually found an event
605
 *      to process.  If no processing occurred, then 0 is returned (this
606
 *      can happen if the TCL_DONT_WAIT flag is set or if there are no
607
 *      event handlers to wait for in the set specified by flags).
608
 *
609
 * Side effects:
610
 *      May delay execution of process while waiting for an event,
611
 *      unless TCL_DONT_WAIT is set in the flags argument.  Event
612
 *      sources are invoked to check for and queue events.  Event
613
 *      handlers may produce arbitrary side effects.
614
 *
615
 *----------------------------------------------------------------------
616
 */
617
 
618
int
619
Tcl_DoOneEvent(flags)
620
    int flags;                  /* Miscellaneous flag values:  may be any
621
                                 * combination of TCL_DONT_WAIT,
622
                                 * TCL_WINDOW_EVENTS, TCL_FILE_EVENTS,
623
                                 * TCL_TIMER_EVENTS, TCL_IDLE_EVENTS, or
624
                                 * others defined by event sources. */
625
{
626
    int result = 0, oldMode;
627
    EventSource *sourcePtr;
628
    Tcl_Time *timePtr;
629
 
630
    if (!initialized) {
631
        InitNotifier();
632
    }
633
 
634
    /*
635
     * The first thing we do is to service any asynchronous event
636
     * handlers.
637
     */
638
 
639
    if (Tcl_AsyncReady()) {
640
        (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
641
        return 1;
642
    }
643
 
644
    /*
645
     * No event flags is equivalent to TCL_ALL_EVENTS.
646
     */
647
 
648
    if ((flags & TCL_ALL_EVENTS) == 0) {
649
        flags |= TCL_ALL_EVENTS;
650
    }
651
 
652
    /*
653
     * Set the service mode to none so notifier event routines won't
654
     * try to service events recursively.
655
     */
656
 
657
    oldMode = notifier.serviceMode;
658
    notifier.serviceMode = TCL_SERVICE_NONE;
659
 
660
    /*
661
     * The core of this procedure is an infinite loop, even though
662
     * we only service one event.  The reason for this is that we
663
     * may be processing events that don't do anything inside of Tcl.
664
     */
665
 
666
    while (1) {
667
 
668
        /*
669
         * If idle events are the only things to service, skip the
670
         * main part of the loop and go directly to handle idle
671
         * events (i.e. don't wait even if TCL_DONT_WAIT isn't set).
672
         */
673
 
674
        if ((flags & TCL_ALL_EVENTS) == TCL_IDLE_EVENTS) {
675
            flags = TCL_IDLE_EVENTS|TCL_DONT_WAIT;
676
            goto idleEvents;
677
        }
678
 
679
        /*
680
         * Ask Tcl to service a queued event, if there are any.
681
         */
682
 
683
        if (Tcl_ServiceEvent(flags)) {
684
            result = 1;
685
            break;
686
        }
687
 
688
        /*
689
         * If TCL_DONT_WAIT is set, be sure to poll rather than
690
         * blocking, otherwise reset the block time to infinity.
691
         */
692
 
693
        if (flags & TCL_DONT_WAIT) {
694
            notifier.blockTime.sec = 0;
695
            notifier.blockTime.usec = 0;
696
            notifier.blockTimeSet = 1;
697
        } else {
698
            notifier.blockTimeSet = 0;
699
        }
700
 
701
        /*
702
         * Set up all the event sources for new events.  This will
703
         * cause the block time to be updated if necessary.
704
         */
705
 
706
        notifier.inTraversal = 1;
707
        for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
708
             sourcePtr = sourcePtr->nextPtr) {
709
            if (sourcePtr->setupProc) {
710
                (sourcePtr->setupProc)(sourcePtr->clientData, flags);
711
            }
712
        }
713
        notifier.inTraversal = 0;
714
 
715
        if ((flags & TCL_DONT_WAIT) || notifier.blockTimeSet) {
716
            timePtr = &notifier.blockTime;
717
        } else {
718
            timePtr = NULL;
719
        }
720
 
721
        /*
722
         * Wait for a new event or a timeout.  If Tcl_WaitForEvent
723
         * returns -1, we should abort Tcl_DoOneEvent.
724
         */
725
 
726
        result = Tcl_WaitForEvent(timePtr);
727
        if (result < 0) {
728
            result = 0;
729
            break;
730
        }
731
 
732
        /*
733
         * Check all the event sources for new events.
734
         */
735
 
736
        for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
737
             sourcePtr = sourcePtr->nextPtr) {
738
            if (sourcePtr->checkProc) {
739
                (sourcePtr->checkProc)(sourcePtr->clientData, flags);
740
            }
741
        }
742
 
743
        /*
744
         * Check for events queued by the notifier or event sources.
745
         */
746
 
747
        if (Tcl_ServiceEvent(flags)) {
748
            result = 1;
749
            break;
750
        }
751
 
752
        /*
753
         * We've tried everything at this point, but nobody we know
754
         * about had anything to do.  Check for idle events.  If none,
755
         * either quit or go back to the top and try again.
756
         */
757
 
758
        idleEvents:
759
        if (flags & TCL_IDLE_EVENTS) {
760
            if (TclServiceIdle()) {
761
                result = 1;
762
                break;
763
            }
764
        }
765
        if (flags & TCL_DONT_WAIT) {
766
            break;
767
        }
768
 
769
        /*
770
         * If Tcl_WaitForEvent has returned 1,
771
         * indicating that one system event has been dispatched
772
         * (and thus that some Tcl code might have been indirectly executed),
773
         * we break out of the loop.
774
         * We do this to give VwaitCmd for instance a chance to check
775
         * if that system event had the side effect of changing the
776
         * variable (so the vwait can return and unwind properly).
777
         *
778
         * NB: We will process idle events if any first, because
779
         *     otherwise we might never do the idle events if the notifier
780
         *     always gets system events.
781
         */
782
 
783
        if (result) {
784
            break;
785
        }
786
 
787
    }
788
 
789
    notifier.serviceMode = oldMode;
790
    return result;
791
}
792
 
793
/*
794
 *----------------------------------------------------------------------
795
 *
796
 * Tcl_ServiceAll --
797
 *
798
 *      This routine checks all of the event sources, processes
799
 *      events that are on the Tcl event queue, and then calls the
800
 *      any idle handlers.  Platform specific notifier callbacks that
801
 *      generate events should call this routine before returning to
802
 *      the system in order to ensure that Tcl gets a chance to
803
 *      process the new events.
804
 *
805
 * Results:
806
 *      Returns 1 if an event or idle handler was invoked, else 0.
807
 *
808
 * Side effects:
809
 *      Anything that an event or idle handler may do.
810
 *
811
 *----------------------------------------------------------------------
812
 */
813
 
814
int
815
Tcl_ServiceAll()
816
{
817
    int result = 0;
818
    EventSource *sourcePtr;
819
 
820
    if (!initialized) {
821
        InitNotifier();
822
    }
823
 
824
    if (notifier.serviceMode == TCL_SERVICE_NONE) {
825
        return result;
826
    }
827
 
828
    /*
829
     * We need to turn off event servicing like we to in Tcl_DoOneEvent,
830
     * to avoid recursive calls.
831
     */
832
 
833
    notifier.serviceMode = TCL_SERVICE_NONE;
834
 
835
    /*
836
     * Check async handlers first.
837
     */
838
 
839
    if (Tcl_AsyncReady()) {
840
        (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
841
    }
842
 
843
    /*
844
     * Make a single pass through all event sources, queued events,
845
     * and idle handlers.  Note that we wait to update the notifier
846
     * timer until the end so we can avoid multiple changes.
847
     */
848
 
849
    notifier.inTraversal = 1;
850
    notifier.blockTimeSet = 0;
851
 
852
    for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
853
         sourcePtr = sourcePtr->nextPtr) {
854
        if (sourcePtr->setupProc) {
855
            (sourcePtr->setupProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
856
        }
857
    }
858
    for (sourcePtr = notifier.firstEventSourcePtr; sourcePtr != NULL;
859
         sourcePtr = sourcePtr->nextPtr) {
860
        if (sourcePtr->checkProc) {
861
            (sourcePtr->checkProc)(sourcePtr->clientData, TCL_ALL_EVENTS);
862
        }
863
    }
864
 
865
    while (Tcl_ServiceEvent(0)) {
866
        result = 1;
867
    }
868
    if (TclServiceIdle()) {
869
        result = 1;
870
    }
871
 
872
    if (!notifier.blockTimeSet) {
873
        Tcl_SetTimer(NULL);
874
    } else {
875
        Tcl_SetTimer(&notifier.blockTime);
876
    }
877
    notifier.inTraversal = 0;
878
    notifier.serviceMode = TCL_SERVICE_ALL;
879
    return result;
880
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.