os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacNotify.c
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacNotify.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,581 @@
1.4 +/*
1.5 + * tclMacNotify.c --
1.6 + *
1.7 + * This file contains Macintosh-specific procedures for the notifier,
1.8 + * which is the lowest-level part of the Tcl event loop. This file
1.9 + * works together with ../generic/tclNotify.c.
1.10 + *
1.11 + * The Mac notifier only polls for system and OS events, so it is process
1.12 + * wide, rather than thread specific. However, this means that the convert
1.13 + * event proc will have to arbitrate which events go to which threads.
1.14 + *
1.15 + * Copyright (c) 1995-1996 Sun Microsystems, Inc.
1.16 + *
1.17 + * See the file "license.terms" for information on usage and redistribution
1.18 + * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
1.19 + *
1.20 + * RCS: @(#) $Id: tclMacNotify.c,v 1.8.4.1 2003/03/21 03:24:08 dgp Exp $
1.21 + */
1.22 +
1.23 +#include "tclInt.h"
1.24 +#include "tclPort.h"
1.25 +#include "tclMac.h"
1.26 +#include "tclMacInt.h"
1.27 +#include <signal.h>
1.28 +#include <Events.h>
1.29 +#include <LowMem.h>
1.30 +#include <Processes.h>
1.31 +#include <Timer.h>
1.32 +#include <Threads.h>
1.33 +
1.34 +
1.35 +/*
1.36 + * This is necessary to work around a bug in Apple's Universal header files
1.37 + * for the CFM68K libraries.
1.38 + */
1.39 +
1.40 +#ifdef __CFM68K__
1.41 +#undef GetEventQueue
1.42 +extern pascal QHdrPtr GetEventQueue(void)
1.43 + THREEWORDINLINE(0x2EBC, 0x0000, 0x014A);
1.44 +#pragma import list GetEventQueue
1.45 +#define GetEvQHdr() GetEventQueue()
1.46 +#endif
1.47 +
1.48 +/*
1.49 + * Need this for replacing Tcl_SetTimer and Tcl_WaitForEvent defined
1.50 + * in THIS file with ones defined in the stub table.
1.51 + */
1.52 +
1.53 +extern TclStubs tclStubs;
1.54 +extern Tcl_NotifierProcs tclOriginalNotifier;
1.55 +
1.56 +/*
1.57 + * The follwing static indicates whether this module has been initialized.
1.58 + */
1.59 +
1.60 +static int initialized = 0;
1.61 +
1.62 +/*
1.63 + * The following structure contains the state information for the
1.64 + * notifier module.
1.65 + */
1.66 +
1.67 +static struct {
1.68 + int timerActive; /* 1 if timer is running. */
1.69 + Tcl_Time timer; /* Time when next timer event is expected. */
1.70 + int flags; /* OR'ed set of flags defined below. */
1.71 + Point lastMousePosition; /* Last known mouse location. */
1.72 + RgnHandle utilityRgn; /* Region used as the mouse region for
1.73 + * WaitNextEvent and the update region when
1.74 + * checking for events. */
1.75 + Tcl_MacConvertEventPtr eventProcPtr;
1.76 + /* This pointer holds the address of the
1.77 + * function that will handle all incoming
1.78 + * Macintosh events. */
1.79 +} notifier;
1.80 +
1.81 +/*
1.82 + * The following defines are used in the flags field of the notifier struct.
1.83 + */
1.84 +
1.85 +#define NOTIFY_IDLE (1<<1) /* Tcl_ServiceIdle should be called. */
1.86 +#define NOTIFY_TIMER (1<<2) /* Tcl_ServiceTimer should be called. */
1.87 +
1.88 +/*
1.89 + * Prototypes for procedures that are referenced only in this file:
1.90 + */
1.91 +
1.92 +static int HandleMacEvents _ANSI_ARGS_((void));
1.93 +static void InitNotifier _ANSI_ARGS_((void));
1.94 +static void NotifierExitHandler _ANSI_ARGS_((
1.95 + ClientData clientData));
1.96 +
1.97 +/*
1.98 + *----------------------------------------------------------------------
1.99 + *
1.100 + * Tcl_InitNotifier --
1.101 + *
1.102 + * Initializes the platform specific notifier state. There is no thread
1.103 + * specific platform notifier on the Mac, so this really doesn't do
1.104 + * anything. However, we need to return the ThreadID, since the generic
1.105 + * notifier hands this back to us in AlertThread.
1.106 + *
1.107 + * Results:
1.108 + * Returns the threadID for this thread.
1.109 + *
1.110 + * Side effects:
1.111 + * None.
1.112 + *
1.113 + *----------------------------------------------------------------------
1.114 + */
1.115 +
1.116 +ClientData
1.117 +Tcl_InitNotifier()
1.118 +{
1.119 +
1.120 +#ifdef TCL_THREADS
1.121 + ThreadID curThread;
1.122 + if (TclMacHaveThreads()) {
1.123 + GetCurrentThread(&curThread);
1.124 + return (ClientData) curThread;
1.125 + } else {
1.126 + return NULL;
1.127 + }
1.128 +#else
1.129 + return NULL;
1.130 +#endif
1.131 +
1.132 +}
1.133 +
1.134 +/*
1.135 + *----------------------------------------------------------------------
1.136 + *
1.137 + * Tcl_FinalizeNotifier --
1.138 + *
1.139 + * This function is called to cleanup the notifier state before
1.140 + * a thread is terminated. There is no platform thread specific
1.141 + * notifier, so this does nothing.
1.142 + *
1.143 + * Results:
1.144 + * None.
1.145 + *
1.146 + * Side effects:
1.147 + * None.
1.148 + *
1.149 + *----------------------------------------------------------------------
1.150 + */
1.151 +
1.152 +void
1.153 +Tcl_FinalizeNotifier(clientData)
1.154 + ClientData clientData; /* Pointer to notifier data. */
1.155 +{
1.156 + /* Nothing to do on the Mac */
1.157 +}
1.158 +
1.159 +/*
1.160 + *----------------------------------------------------------------------
1.161 + *
1.162 + * Tcl_AlertNotifier --
1.163 + *
1.164 + * Wake up the specified notifier from any thread. This routine
1.165 + * is called by the platform independent notifier code whenever
1.166 + * the Tcl_ThreadAlert routine is called. This routine is
1.167 + * guaranteed not to be called on a given notifier after
1.168 + * Tcl_FinalizeNotifier is called for that notifier.
1.169 + *
1.170 + * Results:
1.171 + * None.
1.172 + *
1.173 + * Side effects:
1.174 + * Calls YieldToThread from this thread.
1.175 + *
1.176 + *----------------------------------------------------------------------
1.177 + */
1.178 +
1.179 +void
1.180 +Tcl_AlertNotifier(clientData)
1.181 + ClientData clientData; /* Pointer to thread data. */
1.182 +{
1.183 +
1.184 +#ifdef TCL_THREADS
1.185 + if (TclMacHaveThreads()) {
1.186 + YieldToThread((ThreadID) clientData);
1.187 + }
1.188 +#endif
1.189 +
1.190 +}
1.191 +
1.192 +/*
1.193 + *----------------------------------------------------------------------
1.194 + *
1.195 + * InitNotifier --
1.196 + *
1.197 + * Initializes the notifier structure. Note - this function is never
1.198 + * used.
1.199 + *
1.200 + * Results:
1.201 + * None.
1.202 + *
1.203 + * Side effects:
1.204 + * Creates a new exit handler.
1.205 + *
1.206 + *----------------------------------------------------------------------
1.207 + */
1.208 +
1.209 +static void
1.210 +InitNotifier(void)
1.211 +{
1.212 + initialized = 1;
1.213 + memset(¬ifier, 0, sizeof(notifier));
1.214 + Tcl_CreateExitHandler(NotifierExitHandler, NULL);
1.215 +}
1.216 +
1.217 +/*
1.218 + *----------------------------------------------------------------------
1.219 + *
1.220 + * NotifierExitHandler --
1.221 + *
1.222 + * This function is called to cleanup the notifier state before
1.223 + * Tcl is unloaded. This function is never used, since InitNotifier
1.224 + * isn't either.
1.225 + *
1.226 + * Results:
1.227 + * None.
1.228 + *
1.229 + * Side effects:
1.230 + * None.
1.231 + *
1.232 + *----------------------------------------------------------------------
1.233 + */
1.234 +
1.235 +static void
1.236 +NotifierExitHandler(
1.237 + ClientData clientData) /* Not used. */
1.238 +{
1.239 + initialized = 0;
1.240 +}
1.241 +
1.242 +/*
1.243 + *----------------------------------------------------------------------
1.244 + *
1.245 + * HandleMacEvents --
1.246 + *
1.247 + * This function checks for events from the Macintosh event queue.
1.248 + *
1.249 + * Results:
1.250 + * Returns 1 if event found, 0 otherwise.
1.251 + *
1.252 + * Side effects:
1.253 + * Pulls events off of the Mac event queue and then calls
1.254 + * convertEventProc.
1.255 + *
1.256 + *----------------------------------------------------------------------
1.257 + */
1.258 +
1.259 +static int
1.260 +HandleMacEvents(void)
1.261 +{
1.262 + EventRecord theEvent;
1.263 + int eventFound = 0, needsUpdate = 0;
1.264 + Point currentMouse;
1.265 + WindowRef windowRef;
1.266 + Rect mouseRect;
1.267 +
1.268 + /*
1.269 + * Check for mouse moved events. These events aren't placed on the
1.270 + * system event queue unless we call WaitNextEvent.
1.271 + */
1.272 +
1.273 + GetGlobalMouseTcl(¤tMouse);
1.274 + if ((notifier.eventProcPtr != NULL) &&
1.275 + !EqualPt(currentMouse, notifier.lastMousePosition)) {
1.276 + notifier.lastMousePosition = currentMouse;
1.277 + theEvent.what = nullEvent;
1.278 + if ((*notifier.eventProcPtr)(&theEvent) == true) {
1.279 + eventFound = 1;
1.280 + }
1.281 + }
1.282 +
1.283 + /*
1.284 + * Check for update events. Since update events aren't generated
1.285 + * until we call GetNextEvent, we may need to force a call to
1.286 + * GetNextEvent, even if the queue is empty.
1.287 + */
1.288 +
1.289 + for (windowRef = FrontWindow(); windowRef != NULL;
1.290 + windowRef = GetNextWindow(windowRef)) {
1.291 + GetWindowUpdateRgn(windowRef, notifier.utilityRgn);
1.292 + if (!EmptyRgn(notifier.utilityRgn)) {
1.293 + needsUpdate = 1;
1.294 + break;
1.295 + }
1.296 + }
1.297 +
1.298 + /*
1.299 + * Process events from the OS event queue.
1.300 + */
1.301 +
1.302 + while (needsUpdate || (GetEvQHdr()->qHead != NULL)) {
1.303 + GetGlobalMouseTcl(¤tMouse);
1.304 + SetRect(&mouseRect, currentMouse.h, currentMouse.v,
1.305 + currentMouse.h + 1, currentMouse.v + 1);
1.306 + RectRgn(notifier.utilityRgn, &mouseRect);
1.307 +
1.308 + WaitNextEvent(everyEvent, &theEvent, 5, notifier.utilityRgn);
1.309 + needsUpdate = 0;
1.310 + if ((notifier.eventProcPtr != NULL)
1.311 + && ((*notifier.eventProcPtr)(&theEvent) == true)) {
1.312 + eventFound = 1;
1.313 + }
1.314 + }
1.315 +
1.316 + return eventFound;
1.317 +}
1.318 +
1.319 +/*
1.320 + *----------------------------------------------------------------------
1.321 + *
1.322 + * Tcl_SetTimer --
1.323 + *
1.324 + * This procedure sets the current notifier timer value. The
1.325 + * notifier will ensure that Tcl_ServiceAll() is called after
1.326 + * the specified interval, even if no events have occurred.
1.327 + *
1.328 + * Results:
1.329 + * None.
1.330 + *
1.331 + * Side effects:
1.332 + * Replaces any previous timer.
1.333 + *
1.334 + *----------------------------------------------------------------------
1.335 + */
1.336 +
1.337 +void
1.338 +Tcl_SetTimer(
1.339 + Tcl_Time *timePtr) /* New value for interval timer. */
1.340 +{
1.341 + /*
1.342 + * Allow the notifier to be hooked. This may not make sense
1.343 + * on the Mac, but mirrors the UNIX hook.
1.344 + */
1.345 +
1.346 + if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) {
1.347 + tclStubs.tcl_SetTimer(timePtr);
1.348 + return;
1.349 + }
1.350 +
1.351 + if (!timePtr) {
1.352 + notifier.timerActive = 0;
1.353 + } else {
1.354 + /*
1.355 + * Compute when the timer should fire.
1.356 + */
1.357 +
1.358 + Tcl_GetTime(¬ifier.timer);
1.359 + notifier.timer.sec += timePtr->sec;
1.360 + notifier.timer.usec += timePtr->usec;
1.361 + if (notifier.timer.usec >= 1000000) {
1.362 + notifier.timer.usec -= 1000000;
1.363 + notifier.timer.sec += 1;
1.364 + }
1.365 + notifier.timerActive = 1;
1.366 + }
1.367 +}
1.368 +
1.369 +/*
1.370 + *----------------------------------------------------------------------
1.371 + *
1.372 + * Tcl_ServiceModeHook --
1.373 + *
1.374 + * This function is invoked whenever the service mode changes.
1.375 + *
1.376 + * Results:
1.377 + * None.
1.378 + *
1.379 + * Side effects:
1.380 + * None.
1.381 + *
1.382 + *----------------------------------------------------------------------
1.383 + */
1.384 +
1.385 +void
1.386 +Tcl_ServiceModeHook(mode)
1.387 + int mode; /* Either TCL_SERVICE_ALL, or
1.388 + * TCL_SERVICE_NONE. */
1.389 +{
1.390 +}
1.391 +
1.392 +/*
1.393 + *----------------------------------------------------------------------
1.394 + *
1.395 + * Tcl_WaitForEvent --
1.396 + *
1.397 + * This function is called by Tcl_DoOneEvent to wait for new
1.398 + * events on the message queue. If the block time is 0, then
1.399 + * Tcl_WaitForEvent just polls the event queue without blocking.
1.400 + *
1.401 + * Results:
1.402 + * Always returns 0.
1.403 + *
1.404 + * Side effects:
1.405 + * None.
1.406 + *
1.407 + *----------------------------------------------------------------------
1.408 + */
1.409 +
1.410 +int
1.411 +Tcl_WaitForEvent(
1.412 + Tcl_Time *timePtr) /* Maximum block time. */
1.413 +{
1.414 + int found;
1.415 + EventRecord macEvent;
1.416 + long sleepTime = 5;
1.417 + long ms;
1.418 + Point currentMouse;
1.419 + void * timerToken;
1.420 + Rect mouseRect;
1.421 +
1.422 + /*
1.423 + * Allow the notifier to be hooked. This may not make
1.424 + * sense on the Mac, but mirrors the UNIX hook.
1.425 + */
1.426 +
1.427 + if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) {
1.428 + return tclStubs.tcl_WaitForEvent(timePtr);
1.429 + }
1.430 +
1.431 + /*
1.432 + * Compute the next timeout value.
1.433 + */
1.434 +
1.435 + if (!timePtr) {
1.436 + ms = INT_MAX;
1.437 + } else {
1.438 + ms = (timePtr->sec * 1000) + (timePtr->usec / 1000);
1.439 + }
1.440 + timerToken = TclMacStartTimer((long) ms);
1.441 +
1.442 + /*
1.443 + * Poll the Mac event sources. This loop repeats until something
1.444 + * happens: a timeout, a socket event, mouse motion, or some other
1.445 + * window event. Note that we don't call WaitNextEvent if another
1.446 + * event is found to avoid context switches. This effectively gives
1.447 + * events coming in via WaitNextEvent a slightly lower priority.
1.448 + */
1.449 +
1.450 + found = 0;
1.451 + if (notifier.utilityRgn == NULL) {
1.452 + notifier.utilityRgn = NewRgn();
1.453 + }
1.454 +
1.455 + while (!found) {
1.456 + /*
1.457 + * Check for generated and queued events.
1.458 + */
1.459 +
1.460 + if (HandleMacEvents()) {
1.461 + found = 1;
1.462 + }
1.463 +
1.464 + /*
1.465 + * Check for time out.
1.466 + */
1.467 +
1.468 + if (!found && TclMacTimerExpired(timerToken)) {
1.469 + found = 1;
1.470 + }
1.471 +
1.472 + /*
1.473 + * Check for window events. We may receive a NULL event for
1.474 + * various reasons. 1) the timer has expired, 2) a mouse moved
1.475 + * event is occuring or 3) the os is giving us time for idle
1.476 + * events. Note that we aren't sharing the processor very
1.477 + * well here. We really ought to do a better job of calling
1.478 + * WaitNextEvent for time slicing purposes.
1.479 + */
1.480 +
1.481 + if (!found) {
1.482 + /*
1.483 + * Set up mouse region so we will wake if the mouse is moved.
1.484 + * We do this by defining the smallest possible region around
1.485 + * the current mouse position.
1.486 + */
1.487 +
1.488 + GetGlobalMouseTcl(¤tMouse);
1.489 + SetRect(&mouseRect, currentMouse.h, currentMouse.v,
1.490 + currentMouse.h + 1, currentMouse.v + 1);
1.491 + RectRgn(notifier.utilityRgn, &mouseRect);
1.492 +
1.493 + WaitNextEvent(everyEvent, &macEvent, sleepTime,
1.494 + notifier.utilityRgn);
1.495 +
1.496 + if (notifier.eventProcPtr != NULL) {
1.497 + if ((*notifier.eventProcPtr)(&macEvent) == true) {
1.498 + found = 1;
1.499 + }
1.500 + }
1.501 + }
1.502 + }
1.503 + TclMacRemoveTimer(timerToken);
1.504 +
1.505 + /*
1.506 + * Yield time to nay other thread at this point. If we find that the
1.507 + * apps thrash too switching between threads, we can put a timer here,
1.508 + * and only yield when the timer fires.
1.509 + */
1.510 +
1.511 + if (TclMacHaveThreads()) {
1.512 + YieldToAnyThread();
1.513 + }
1.514 +
1.515 + return 0;
1.516 +}
1.517 +
1.518 +/*
1.519 + *----------------------------------------------------------------------
1.520 + *
1.521 + * Tcl_Sleep --
1.522 + *
1.523 + * Delay execution for the specified number of milliseconds. This
1.524 + * is not a very good call to make. It will block the system -
1.525 + * you will not even be able to switch applications.
1.526 + *
1.527 + * Results:
1.528 + * None.
1.529 + *
1.530 + * Side effects:
1.531 + * Time passes.
1.532 + *
1.533 + *----------------------------------------------------------------------
1.534 + */
1.535 +
1.536 +void
1.537 +Tcl_Sleep(
1.538 + int ms) /* Number of milliseconds to sleep. */
1.539 +{
1.540 + EventRecord dummy;
1.541 + void *timerToken;
1.542 +
1.543 + if (ms <= 0) {
1.544 + return;
1.545 + }
1.546 +
1.547 + timerToken = TclMacStartTimer((long) ms);
1.548 + while (1) {
1.549 + WaitNextEvent(0, &dummy, (ms / 16.66) + 1, NULL);
1.550 + if (TclMacHaveThreads()) {
1.551 + YieldToAnyThread();
1.552 + }
1.553 + if (TclMacTimerExpired(timerToken)) {
1.554 + break;
1.555 + }
1.556 + }
1.557 + TclMacRemoveTimer(timerToken);
1.558 +}
1.559 +
1.560 +/*
1.561 + *----------------------------------------------------------------------
1.562 + *
1.563 + * Tcl_MacSetEventProc --
1.564 + *
1.565 + * This function sets the event handling procedure for the
1.566 + * application. This function will be passed all incoming Mac
1.567 + * events. This function usually controls the console or some
1.568 + * other entity like Tk.
1.569 + *
1.570 + * Results:
1.571 + * None.
1.572 + *
1.573 + * Side effects:
1.574 + * Changes the event handling function.
1.575 + *
1.576 + *----------------------------------------------------------------------
1.577 + */
1.578 +
1.579 +void
1.580 +Tcl_MacSetEventProc(
1.581 + Tcl_MacConvertEventPtr procPtr)
1.582 +{
1.583 + notifier.eventProcPtr = procPtr;
1.584 +}