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 * Copyright (c) 1995-1996 Sun Microsystems, Inc.
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 * SCCS: @(#) tclMacNotify.c 1.36 97/05/07 19:09:29
17 /* Move this include up otherwise tclPort.h tried to redefine signals */
18 #include <sys/signal.h>
23 #include "tclMacInt.h"
27 #include <Processes.h>
32 * This is necessary to work around a bug in Apple's Universal header files
33 * for the CFM68K libraries.
38 extern pascal QHdrPtr
GetEventQueue(void)
39 THREEWORDINLINE(0x2EBC, 0x0000, 0x014A);
40 #pragma import list GetEventQueue
41 #define GetEvQHdr() GetEventQueue()
45 * The follwing static indicates whether this module has been initialized.
48 static int initialized
= 0;
51 * The following structure contains the state information for the
56 int timerActive
; /* 1 if timer is running. */
57 Tcl_Time timer
; /* Time when next timer event is expected. */
58 int flags
; /* OR'ed set of flags defined below. */
59 Point lastMousePosition
; /* Last known mouse location. */
60 RgnHandle utilityRgn
; /* Region used as the mouse region for
61 * WaitNextEvent and the update region when
62 * checking for events. */
63 Tcl_MacConvertEventPtr eventProcPtr
;
64 /* This pointer holds the address of the
65 * function that will handle all incoming
66 * Macintosh events. */
70 * The following defines are used in the flags field of the notifier struct.
73 #define NOTIFY_IDLE (1<<1) /* Tcl_ServiceIdle should be called. */
74 #define NOTIFY_TIMER (1<<2) /* Tcl_ServiceTimer should be called. */
77 * Prototypes for procedures that are referenced only in this file:
80 static int HandleMacEvents
_ANSI_ARGS_((void));
81 static void InitNotifier
_ANSI_ARGS_((void));
82 static void NotifierExitHandler
_ANSI_ARGS_((
83 ClientData clientData
));
86 *----------------------------------------------------------------------
90 * Initializes the notifier structure.
96 * Creates a new exit handler.
98 *----------------------------------------------------------------------
105 memset(¬ifier
, 0, sizeof(notifier
));
106 Tcl_CreateExitHandler(NotifierExitHandler
, NULL
);
110 *----------------------------------------------------------------------
112 * NotifierExitHandler --
114 * This function is called to cleanup the notifier state before
123 *----------------------------------------------------------------------
128 ClientData clientData
) /* Not used. */
134 *----------------------------------------------------------------------
138 * This function checks for events from the Macintosh event queue.
141 * Returns 1 if event found, 0 otherwise.
144 * Pulls events off of the Mac event queue and then calls
147 *----------------------------------------------------------------------
151 HandleMacEvents(void)
153 EventRecord theEvent
;
154 int eventFound
= 0, needsUpdate
= 0;
160 * Check for mouse moved events. These events aren't placed on the
161 * system event queue unless we call WaitNextEvent.
164 GetGlobalMouse(¤tMouse
);
165 if ((notifier
.eventProcPtr
!= NULL
) &&
166 !EqualPt(currentMouse
, notifier
.lastMousePosition
)) {
167 notifier
.lastMousePosition
= currentMouse
;
168 theEvent
.what
= nullEvent
;
169 if ((*notifier
.eventProcPtr
)(&theEvent
) == true) {
175 * Check for update events. Since update events aren't generated
176 * until we call GetNextEvent, we may need to force a call to
177 * GetNextEvent, even if the queue is empty.
180 for (windowRef
= FrontWindow(); windowRef
!= NULL
;
181 windowRef
= GetNextWindow(windowRef
)) {
182 GetWindowUpdateRgn(windowRef
, notifier
.utilityRgn
);
183 if (!EmptyRgn(notifier
.utilityRgn
)) {
190 * Process events from the OS event queue.
193 while (needsUpdate
|| (GetEvQHdr()->qHead
!= NULL
)) {
194 GetGlobalMouse(¤tMouse
);
195 SetRect(&mouseRect
, currentMouse
.h
, currentMouse
.v
,
196 currentMouse
.h
+ 1, currentMouse
.v
+ 1);
197 RectRgn(notifier
.utilityRgn
, &mouseRect
);
199 WaitNextEvent(everyEvent
, &theEvent
, 5, notifier
.utilityRgn
);
201 if ((notifier
.eventProcPtr
!= NULL
)
202 && ((*notifier
.eventProcPtr
)(&theEvent
) == true)) {
211 *----------------------------------------------------------------------
215 * This procedure sets the current notifier timer value. The
216 * notifier will ensure that Tcl_ServiceAll() is called after
217 * the specified interval, even if no events have occurred.
223 * Replaces any previous timer.
225 *----------------------------------------------------------------------
230 Tcl_Time
*timePtr
) /* New value for interval timer. */
233 notifier
.timerActive
= 0;
236 * Compute when the timer should fire.
239 TclpGetTime(¬ifier
.timer
);
240 notifier
.timer
.sec
+= timePtr
->sec
;
241 notifier
.timer
.usec
+= timePtr
->usec
;
242 if (notifier
.timer
.usec
>= 1000000) {
243 notifier
.timer
.usec
-= 1000000;
244 notifier
.timer
.sec
+= 1;
246 notifier
.timerActive
= 1;
251 *----------------------------------------------------------------------
253 * Tcl_WaitForEvent --
255 * This function is called by Tcl_DoOneEvent to wait for new
256 * events on the message queue. If the block time is 0, then
257 * Tcl_WaitForEvent just polls the event queue without blocking.
265 *----------------------------------------------------------------------
270 Tcl_Time
*timePtr
) /* Maximum block time. */
273 EventRecord macEvent
;
281 * Compute the next timeout value.
287 ms
= (timePtr
->sec
* 1000) + (timePtr
->usec
/ 1000);
289 timerToken
= TclMacStartTimer((long) ms
);
292 * Poll the Mac event sources. This loop repeats until something
293 * happens: a timeout, a socket event, mouse motion, or some other
294 * window event. Note that we don't call WaitNextEvent if another
295 * event is found to avoid context switches. This effectively gives
296 * events coming in via WaitNextEvent a slightly lower priority.
300 if (notifier
.utilityRgn
== NULL
) {
301 notifier
.utilityRgn
= NewRgn();
306 * Check for generated and queued events.
309 if (HandleMacEvents()) {
314 * Check for time out.
317 if (!found
&& TclMacTimerExpired(timerToken
)) {
322 * Mod by Jack: poll for select() events. Code is in TclSelectNotify.c
325 int Tcl_PollSelectEvent(void);
326 if (!found
&& Tcl_PollSelectEvent())
331 * Check for window events. We may receive a NULL event for
332 * various reasons. 1) the timer has expired, 2) a mouse moved
333 * event is occuring or 3) the os is giving us time for idle
334 * events. Note that we aren't sharing the processor very
335 * well here. We really ought to do a better job of calling
336 * WaitNextEvent for time slicing purposes.
341 * Set up mouse region so we will wake if the mouse is moved.
342 * We do this by defining the smallest possible region around
343 * the current mouse position.
346 GetGlobalMouse(¤tMouse
);
347 SetRect(&mouseRect
, currentMouse
.h
, currentMouse
.v
,
348 currentMouse
.h
+ 1, currentMouse
.v
+ 1);
349 RectRgn(notifier
.utilityRgn
, &mouseRect
);
351 WaitNextEvent(everyEvent
, &macEvent
, sleepTime
,
352 notifier
.utilityRgn
);
354 if (notifier
.eventProcPtr
!= NULL
) {
355 if ((*notifier
.eventProcPtr
)(&macEvent
) == true) {
361 TclMacRemoveTimer(timerToken
);
366 *----------------------------------------------------------------------
370 * Delay execution for the specified number of milliseconds. This
371 * is not a very good call to make. It will block the system -
372 * you will not even be able to switch applications.
380 *----------------------------------------------------------------------
385 int ms
) /* Number of milliseconds to sleep. */
394 timerToken
= TclMacStartTimer((long) ms
);
396 WaitNextEvent(0, &dummy
, (ms
/ 16.66) + 1, NULL
);
398 if (TclMacTimerExpired(timerToken
)) {
402 TclMacRemoveTimer(timerToken
);
406 *----------------------------------------------------------------------
408 * Tcl_MacSetEventProc --
410 * This function sets the event handling procedure for the
411 * application. This function will be passed all incoming Mac
412 * events. This function usually controls the console or some
413 * other entity like Tk.
419 * Changes the event handling function.
421 *----------------------------------------------------------------------
426 Tcl_MacConvertEventPtr procPtr
)
428 notifier
.eventProcPtr
= procPtr
;