os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacNotify.c
First public contribution.
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.
8 * The Mac notifier only polls for system and OS events, so it is process
9 * wide, rather than thread specific. However, this means that the convert
10 * event proc will have to arbitrate which events go to which threads.
12 * Copyright (c) 1995-1996 Sun Microsystems, Inc.
14 * See the file "license.terms" for information on usage and redistribution
15 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
17 * RCS: @(#) $Id: tclMacNotify.c,v 1.8.4.1 2003/03/21 03:24:08 dgp Exp $
23 #include "tclMacInt.h"
27 #include <Processes.h>
33 * This is necessary to work around a bug in Apple's Universal header files
34 * for the CFM68K libraries.
39 extern pascal QHdrPtr GetEventQueue(void)
40 THREEWORDINLINE(0x2EBC, 0x0000, 0x014A);
41 #pragma import list GetEventQueue
42 #define GetEvQHdr() GetEventQueue()
46 * Need this for replacing Tcl_SetTimer and Tcl_WaitForEvent defined
47 * in THIS file with ones defined in the stub table.
50 extern TclStubs tclStubs;
51 extern Tcl_NotifierProcs tclOriginalNotifier;
54 * The follwing static indicates whether this module has been initialized.
57 static int initialized = 0;
60 * The following structure contains the state information for the
65 int timerActive; /* 1 if timer is running. */
66 Tcl_Time timer; /* Time when next timer event is expected. */
67 int flags; /* OR'ed set of flags defined below. */
68 Point lastMousePosition; /* Last known mouse location. */
69 RgnHandle utilityRgn; /* Region used as the mouse region for
70 * WaitNextEvent and the update region when
71 * checking for events. */
72 Tcl_MacConvertEventPtr eventProcPtr;
73 /* This pointer holds the address of the
74 * function that will handle all incoming
75 * Macintosh events. */
79 * The following defines are used in the flags field of the notifier struct.
82 #define NOTIFY_IDLE (1<<1) /* Tcl_ServiceIdle should be called. */
83 #define NOTIFY_TIMER (1<<2) /* Tcl_ServiceTimer should be called. */
86 * Prototypes for procedures that are referenced only in this file:
89 static int HandleMacEvents _ANSI_ARGS_((void));
90 static void InitNotifier _ANSI_ARGS_((void));
91 static void NotifierExitHandler _ANSI_ARGS_((
92 ClientData clientData));
95 *----------------------------------------------------------------------
99 * Initializes the platform specific notifier state. There is no thread
100 * specific platform notifier on the Mac, so this really doesn't do
101 * anything. However, we need to return the ThreadID, since the generic
102 * notifier hands this back to us in AlertThread.
105 * Returns the threadID for this thread.
110 *----------------------------------------------------------------------
119 if (TclMacHaveThreads()) {
120 GetCurrentThread(&curThread);
121 return (ClientData) curThread;
132 *----------------------------------------------------------------------
134 * Tcl_FinalizeNotifier --
136 * This function is called to cleanup the notifier state before
137 * a thread is terminated. There is no platform thread specific
138 * notifier, so this does nothing.
146 *----------------------------------------------------------------------
150 Tcl_FinalizeNotifier(clientData)
151 ClientData clientData; /* Pointer to notifier data. */
153 /* Nothing to do on the Mac */
157 *----------------------------------------------------------------------
159 * Tcl_AlertNotifier --
161 * Wake up the specified notifier from any thread. This routine
162 * is called by the platform independent notifier code whenever
163 * the Tcl_ThreadAlert routine is called. This routine is
164 * guaranteed not to be called on a given notifier after
165 * Tcl_FinalizeNotifier is called for that notifier.
171 * Calls YieldToThread from this thread.
173 *----------------------------------------------------------------------
177 Tcl_AlertNotifier(clientData)
178 ClientData clientData; /* Pointer to thread data. */
182 if (TclMacHaveThreads()) {
183 YieldToThread((ThreadID) clientData);
190 *----------------------------------------------------------------------
194 * Initializes the notifier structure. Note - this function is never
201 * Creates a new exit handler.
203 *----------------------------------------------------------------------
210 memset(¬ifier, 0, sizeof(notifier));
211 Tcl_CreateExitHandler(NotifierExitHandler, NULL);
215 *----------------------------------------------------------------------
217 * NotifierExitHandler --
219 * This function is called to cleanup the notifier state before
220 * Tcl is unloaded. This function is never used, since InitNotifier
229 *----------------------------------------------------------------------
234 ClientData clientData) /* Not used. */
240 *----------------------------------------------------------------------
244 * This function checks for events from the Macintosh event queue.
247 * Returns 1 if event found, 0 otherwise.
250 * Pulls events off of the Mac event queue and then calls
253 *----------------------------------------------------------------------
257 HandleMacEvents(void)
259 EventRecord theEvent;
260 int eventFound = 0, needsUpdate = 0;
266 * Check for mouse moved events. These events aren't placed on the
267 * system event queue unless we call WaitNextEvent.
270 GetGlobalMouseTcl(¤tMouse);
271 if ((notifier.eventProcPtr != NULL) &&
272 !EqualPt(currentMouse, notifier.lastMousePosition)) {
273 notifier.lastMousePosition = currentMouse;
274 theEvent.what = nullEvent;
275 if ((*notifier.eventProcPtr)(&theEvent) == true) {
281 * Check for update events. Since update events aren't generated
282 * until we call GetNextEvent, we may need to force a call to
283 * GetNextEvent, even if the queue is empty.
286 for (windowRef = FrontWindow(); windowRef != NULL;
287 windowRef = GetNextWindow(windowRef)) {
288 GetWindowUpdateRgn(windowRef, notifier.utilityRgn);
289 if (!EmptyRgn(notifier.utilityRgn)) {
296 * Process events from the OS event queue.
299 while (needsUpdate || (GetEvQHdr()->qHead != NULL)) {
300 GetGlobalMouseTcl(¤tMouse);
301 SetRect(&mouseRect, currentMouse.h, currentMouse.v,
302 currentMouse.h + 1, currentMouse.v + 1);
303 RectRgn(notifier.utilityRgn, &mouseRect);
305 WaitNextEvent(everyEvent, &theEvent, 5, notifier.utilityRgn);
307 if ((notifier.eventProcPtr != NULL)
308 && ((*notifier.eventProcPtr)(&theEvent) == true)) {
317 *----------------------------------------------------------------------
321 * This procedure sets the current notifier timer value. The
322 * notifier will ensure that Tcl_ServiceAll() is called after
323 * the specified interval, even if no events have occurred.
329 * Replaces any previous timer.
331 *----------------------------------------------------------------------
336 Tcl_Time *timePtr) /* New value for interval timer. */
339 * Allow the notifier to be hooked. This may not make sense
340 * on the Mac, but mirrors the UNIX hook.
343 if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) {
344 tclStubs.tcl_SetTimer(timePtr);
349 notifier.timerActive = 0;
352 * Compute when the timer should fire.
355 Tcl_GetTime(¬ifier.timer);
356 notifier.timer.sec += timePtr->sec;
357 notifier.timer.usec += timePtr->usec;
358 if (notifier.timer.usec >= 1000000) {
359 notifier.timer.usec -= 1000000;
360 notifier.timer.sec += 1;
362 notifier.timerActive = 1;
367 *----------------------------------------------------------------------
369 * Tcl_ServiceModeHook --
371 * This function is invoked whenever the service mode changes.
379 *----------------------------------------------------------------------
383 Tcl_ServiceModeHook(mode)
384 int mode; /* Either TCL_SERVICE_ALL, or
385 * TCL_SERVICE_NONE. */
390 *----------------------------------------------------------------------
392 * Tcl_WaitForEvent --
394 * This function is called by Tcl_DoOneEvent to wait for new
395 * events on the message queue. If the block time is 0, then
396 * Tcl_WaitForEvent just polls the event queue without blocking.
404 *----------------------------------------------------------------------
409 Tcl_Time *timePtr) /* Maximum block time. */
412 EventRecord macEvent;
420 * Allow the notifier to be hooked. This may not make
421 * sense on the Mac, but mirrors the UNIX hook.
424 if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) {
425 return tclStubs.tcl_WaitForEvent(timePtr);
429 * Compute the next timeout value.
435 ms = (timePtr->sec * 1000) + (timePtr->usec / 1000);
437 timerToken = TclMacStartTimer((long) ms);
440 * Poll the Mac event sources. This loop repeats until something
441 * happens: a timeout, a socket event, mouse motion, or some other
442 * window event. Note that we don't call WaitNextEvent if another
443 * event is found to avoid context switches. This effectively gives
444 * events coming in via WaitNextEvent a slightly lower priority.
448 if (notifier.utilityRgn == NULL) {
449 notifier.utilityRgn = NewRgn();
454 * Check for generated and queued events.
457 if (HandleMacEvents()) {
462 * Check for time out.
465 if (!found && TclMacTimerExpired(timerToken)) {
470 * Check for window events. We may receive a NULL event for
471 * various reasons. 1) the timer has expired, 2) a mouse moved
472 * event is occuring or 3) the os is giving us time for idle
473 * events. Note that we aren't sharing the processor very
474 * well here. We really ought to do a better job of calling
475 * WaitNextEvent for time slicing purposes.
480 * Set up mouse region so we will wake if the mouse is moved.
481 * We do this by defining the smallest possible region around
482 * the current mouse position.
485 GetGlobalMouseTcl(¤tMouse);
486 SetRect(&mouseRect, currentMouse.h, currentMouse.v,
487 currentMouse.h + 1, currentMouse.v + 1);
488 RectRgn(notifier.utilityRgn, &mouseRect);
490 WaitNextEvent(everyEvent, &macEvent, sleepTime,
491 notifier.utilityRgn);
493 if (notifier.eventProcPtr != NULL) {
494 if ((*notifier.eventProcPtr)(&macEvent) == true) {
500 TclMacRemoveTimer(timerToken);
503 * Yield time to nay other thread at this point. If we find that the
504 * apps thrash too switching between threads, we can put a timer here,
505 * and only yield when the timer fires.
508 if (TclMacHaveThreads()) {
516 *----------------------------------------------------------------------
520 * Delay execution for the specified number of milliseconds. This
521 * is not a very good call to make. It will block the system -
522 * you will not even be able to switch applications.
530 *----------------------------------------------------------------------
535 int ms) /* Number of milliseconds to sleep. */
544 timerToken = TclMacStartTimer((long) ms);
546 WaitNextEvent(0, &dummy, (ms / 16.66) + 1, NULL);
547 if (TclMacHaveThreads()) {
550 if (TclMacTimerExpired(timerToken)) {
554 TclMacRemoveTimer(timerToken);
558 *----------------------------------------------------------------------
560 * Tcl_MacSetEventProc --
562 * This function sets the event handling procedure for the
563 * application. This function will be passed all incoming Mac
564 * events. This function usually controls the console or some
565 * other entity like Tk.
571 * Changes the event handling function.
573 *----------------------------------------------------------------------
578 Tcl_MacConvertEventPtr procPtr)
580 notifier.eventProcPtr = procPtr;