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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tcl/] [mac/] [tclMacNotify.c] - Blame information for rev 1767

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tclMacNotify.c --
3
 *
4
 *      This file contains Macintosh-specific procedures for the notifier,
5
 *      which is the lowest-level part of the Tcl event loop.  This file
6
 *      works together with ../generic/tclNotify.c.
7
 *
8
 * Copyright (c) 1995-1996 Sun Microsystems, Inc.
9
 *
10
 * See the file "license.terms" for information on usage and redistribution
11
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12
 *
13
 * RCS: @(#) $Id: tclMacNotify.c,v 1.1.1.1 2002-01-16 10:25:30 markom Exp $
14
 */
15
 
16
#include "tclInt.h"
17
#include "tclPort.h"
18
#include "tclMac.h"
19
#include "tclMacInt.h"
20
#include <signal.h>
21
#include <Events.h>
22
#include <LowMem.h>
23
#include <Processes.h>
24
#include <Timer.h>
25
 
26
 
27
/*
28
 * This is necessary to work around a bug in Apple's Universal header files
29
 * for the CFM68K libraries.
30
 */
31
 
32
#ifdef __CFM68K__
33
#undef GetEventQueue
34
extern pascal QHdrPtr GetEventQueue(void)
35
 THREEWORDINLINE(0x2EBC, 0x0000, 0x014A);
36
#pragma import list GetEventQueue
37
#define GetEvQHdr() GetEventQueue()
38
#endif
39
 
40
/*
41
 * The follwing static indicates whether this module has been initialized.
42
 */
43
 
44
static int initialized = 0;
45
 
46
/*
47
 * The following structure contains the state information for the
48
 * notifier module.
49
 */
50
 
51
static struct {
52
    int timerActive;            /* 1 if timer is running. */
53
    Tcl_Time timer;             /* Time when next timer event is expected. */
54
    int flags;                  /* OR'ed set of flags defined below. */
55
    Point lastMousePosition;    /* Last known mouse location. */
56
    RgnHandle utilityRgn;       /* Region used as the mouse region for
57
                                 * WaitNextEvent and the update region when
58
                                 * checking for events. */
59
    Tcl_MacConvertEventPtr eventProcPtr;
60
                                /* This pointer holds the address of the
61
                                 * function that will handle all incoming
62
                                 * Macintosh events. */
63
} notifier;
64
 
65
/*
66
 * The following defines are used in the flags field of the notifier struct.
67
 */
68
 
69
#define NOTIFY_IDLE     (1<<1)  /* Tcl_ServiceIdle should be called. */
70
#define NOTIFY_TIMER    (1<<2)  /* Tcl_ServiceTimer should be called. */
71
 
72
/*
73
 * Prototypes for procedures that are referenced only in this file:
74
 */
75
 
76
static int              HandleMacEvents _ANSI_ARGS_((void));
77
static void             InitNotifier _ANSI_ARGS_((void));
78
static void             NotifierExitHandler _ANSI_ARGS_((
79
                            ClientData clientData));
80
 
81
/*
82
 *----------------------------------------------------------------------
83
 *
84
 * InitNotifier --
85
 *
86
 *      Initializes the notifier structure.
87
 *
88
 * Results:
89
 *      None.
90
 *
91
 * Side effects:
92
 *      Creates a new exit handler.
93
 *
94
 *----------------------------------------------------------------------
95
 */
96
 
97
static void
98
InitNotifier(void)
99
{
100
    initialized = 1;
101
    memset(&notifier, 0, sizeof(notifier));
102
    Tcl_CreateExitHandler(NotifierExitHandler, NULL);
103
}
104
 
105
/*
106
 *----------------------------------------------------------------------
107
 *
108
 * NotifierExitHandler --
109
 *
110
 *      This function is called to cleanup the notifier state before
111
 *      Tcl is unloaded.
112
 *
113
 * Results:
114
 *      None.
115
 *
116
 * Side effects:
117
 *      None.
118
 *
119
 *----------------------------------------------------------------------
120
 */
121
 
122
static void
123
NotifierExitHandler(
124
    ClientData clientData)      /* Not used. */
125
{
126
    initialized = 0;
127
}
128
 
129
/*
130
 *----------------------------------------------------------------------
131
 *
132
 * HandleMacEvents --
133
 *
134
 *      This function checks for events from the Macintosh event queue.
135
 *
136
 * Results:
137
 *      Returns 1 if event found, 0 otherwise.
138
 *
139
 * Side effects:
140
 *      Pulls events off of the Mac event queue and then calls
141
 *      convertEventProc.
142
 *
143
 *----------------------------------------------------------------------
144
 */
145
 
146
static int
147
HandleMacEvents(void)
148
{
149
    EventRecord theEvent;
150
    int eventFound = 0, needsUpdate = 0;
151
    Point currentMouse;
152
    WindowRef windowRef;
153
    Rect mouseRect;
154
 
155
    /*
156
     * Check for mouse moved events.  These events aren't placed on the
157
     * system event queue unless we call WaitNextEvent.
158
     */
159
 
160
    GetGlobalMouse(&currentMouse);
161
    if ((notifier.eventProcPtr != NULL) &&
162
            !EqualPt(currentMouse, notifier.lastMousePosition)) {
163
        notifier.lastMousePosition = currentMouse;
164
        theEvent.what = nullEvent;
165
        if ((*notifier.eventProcPtr)(&theEvent) == true) {
166
            eventFound = 1;
167
        }
168
    }
169
 
170
    /*
171
     * Check for update events.  Since update events aren't generated
172
     * until we call GetNextEvent, we may need to force a call to
173
     * GetNextEvent, even if the queue is empty.
174
     */
175
 
176
    for (windowRef = FrontWindow(); windowRef != NULL;
177
            windowRef = GetNextWindow(windowRef)) {
178
        GetWindowUpdateRgn(windowRef, notifier.utilityRgn);
179
        if (!EmptyRgn(notifier.utilityRgn)) {
180
            needsUpdate = 1;
181
            break;
182
        }
183
    }
184
 
185
    /*
186
     * Process events from the OS event queue.
187
     */
188
 
189
    while (needsUpdate || (GetEvQHdr()->qHead != NULL)) {
190
        GetGlobalMouse(&currentMouse);
191
        SetRect(&mouseRect, currentMouse.h, currentMouse.v,
192
                currentMouse.h + 1, currentMouse.v + 1);
193
        RectRgn(notifier.utilityRgn, &mouseRect);
194
 
195
        WaitNextEvent(everyEvent, &theEvent, 5, notifier.utilityRgn);
196
        needsUpdate = 0;
197
        if ((notifier.eventProcPtr != NULL)
198
                && ((*notifier.eventProcPtr)(&theEvent) == true)) {
199
            eventFound = 1;
200
        }
201
    }
202
 
203
    return eventFound;
204
}
205
 
206
/*
207
 *----------------------------------------------------------------------
208
 *
209
 * Tcl_SetTimer --
210
 *
211
 *      This procedure sets the current notifier timer value.  The
212
 *      notifier will ensure that Tcl_ServiceAll() is called after
213
 *      the specified interval, even if no events have occurred.
214
 *
215
 * Results:
216
 *      None.
217
 *
218
 * Side effects:
219
 *      Replaces any previous timer.
220
 *
221
 *----------------------------------------------------------------------
222
 */
223
 
224
void
225
Tcl_SetTimer(
226
    Tcl_Time *timePtr)          /* New value for interval timer. */
227
{
228
    if (!timePtr) {
229
        notifier.timerActive = 0;
230
    } else {
231
        /*
232
         * Compute when the timer should fire.
233
         */
234
 
235
        TclpGetTime(&notifier.timer);
236
        notifier.timer.sec += timePtr->sec;
237
        notifier.timer.usec += timePtr->usec;
238
        if (notifier.timer.usec >= 1000000) {
239
            notifier.timer.usec -= 1000000;
240
            notifier.timer.sec += 1;
241
        }
242
        notifier.timerActive = 1;
243
    }
244
}
245
 
246
/*
247
 *----------------------------------------------------------------------
248
 *
249
 * Tcl_WaitForEvent --
250
 *
251
 *      This function is called by Tcl_DoOneEvent to wait for new
252
 *      events on the message queue.  If the block time is 0, then
253
 *      Tcl_WaitForEvent just polls the event queue without blocking.
254
 *
255
 * Results:
256
 *      Always returns 0.
257
 *
258
 * Side effects:
259
 *      None.
260
 *
261
 *----------------------------------------------------------------------
262
 */
263
 
264
int
265
Tcl_WaitForEvent(
266
    Tcl_Time *timePtr)          /* Maximum block time. */
267
{
268
    int found;
269
    EventRecord macEvent;
270
    long sleepTime = 5;
271
    long ms;
272
    Point currentMouse;
273
    void * timerToken;
274
    Rect mouseRect;
275
 
276
    /*
277
     * Compute the next timeout value.
278
     */
279
 
280
    if (!timePtr) {
281
        ms = INT_MAX;
282
    } else {
283
        ms = (timePtr->sec * 1000) + (timePtr->usec / 1000);
284
    }
285
    timerToken = TclMacStartTimer((long) ms);
286
 
287
    /*
288
     * Poll the Mac event sources.  This loop repeats until something
289
     * happens: a timeout, a socket event, mouse motion, or some other
290
     * window event.  Note that we don't call WaitNextEvent if another
291
     * event is found to avoid context switches.  This effectively gives
292
     * events coming in via WaitNextEvent a slightly lower priority.
293
     */
294
 
295
    found = 0;
296
    if (notifier.utilityRgn == NULL) {
297
        notifier.utilityRgn = NewRgn();
298
    }
299
 
300
    while (!found) {
301
        /*
302
         * Check for generated and queued events.
303
         */
304
 
305
        if (HandleMacEvents()) {
306
            found = 1;
307
        }
308
 
309
        /*
310
         * Check for time out.
311
         */
312
 
313
        if (!found && TclMacTimerExpired(timerToken)) {
314
            found = 1;
315
        }
316
 
317
        /*
318
         * Check for window events.  We may receive a NULL event for
319
         * various reasons. 1) the timer has expired, 2) a mouse moved
320
         * event is occuring or 3) the os is giving us time for idle
321
         * events.  Note that we aren't sharing the processor very
322
         * well here.  We really ought to do a better job of calling
323
         * WaitNextEvent for time slicing purposes.
324
         */
325
 
326
        if (!found) {
327
            /*
328
             * Set up mouse region so we will wake if the mouse is moved.
329
             * We do this by defining the smallest possible region around
330
             * the current mouse position.
331
             */
332
 
333
            GetGlobalMouse(&currentMouse);
334
            SetRect(&mouseRect, currentMouse.h, currentMouse.v,
335
                    currentMouse.h + 1, currentMouse.v + 1);
336
            RectRgn(notifier.utilityRgn, &mouseRect);
337
 
338
            WaitNextEvent(everyEvent, &macEvent, sleepTime,
339
                    notifier.utilityRgn);
340
 
341
            if (notifier.eventProcPtr != NULL) {
342
                if ((*notifier.eventProcPtr)(&macEvent) == true) {
343
                    found = 1;
344
                }
345
            }
346
        }
347
    }
348
    TclMacRemoveTimer(timerToken);
349
    return 0;
350
}
351
 
352
/*
353
 *----------------------------------------------------------------------
354
 *
355
 * Tcl_Sleep --
356
 *
357
 *      Delay execution for the specified number of milliseconds.  This
358
 *      is not a very good call to make.  It will block the system -
359
 *      you will not even be able to switch applications.
360
 *
361
 * Results:
362
 *      None.
363
 *
364
 * Side effects:
365
 *      Time passes.
366
 *
367
 *----------------------------------------------------------------------
368
 */
369
 
370
void
371
Tcl_Sleep(
372
    int ms)                     /* Number of milliseconds to sleep. */
373
{
374
    EventRecord dummy;
375
    void *timerToken;
376
 
377
    if (ms <= 0) {
378
        return;
379
    }
380
 
381
    timerToken = TclMacStartTimer((long) ms);
382
    while (1) {
383
        WaitNextEvent(0, &dummy, (ms / 16.66) + 1, NULL);
384
 
385
        if (TclMacTimerExpired(timerToken)) {
386
            break;
387
        }
388
    }
389
    TclMacRemoveTimer(timerToken);
390
}
391
 
392
/*
393
 *----------------------------------------------------------------------
394
 *
395
 * Tcl_MacSetEventProc --
396
 *
397
 *      This function sets the event handling procedure for the
398
 *      application.  This function will be passed all incoming Mac
399
 *      events.  This function usually controls the console or some
400
 *      other entity like Tk.
401
 *
402
 * Results:
403
 *      None.
404
 *
405
 * Side effects:
406
 *      Changes the event handling function.
407
 *
408
 *----------------------------------------------------------------------
409
 */
410
 
411
void
412
Tcl_MacSetEventProc(
413
    Tcl_MacConvertEventPtr procPtr)
414
{
415
    notifier.eventProcPtr = procPtr;
416
}

powered by: WebSVN 2.1.0

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