os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/mac/tclMacNotify.c
changeset 0 bde4ae8d615e
     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(&notifier, 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(&currentMouse);
   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(&currentMouse);
   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(&notifier.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(&currentMouse);
   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 +}