//-----------------------------------------------------------------------------
// Torque Game Engine 
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------

#include "platform/types.h"
#if defined(TORQUE_OS_MAC_OSX)
// AAAAAAAAARGGGH.
// OSX Frameworks version of AGL.h includes CoreServices, which hits the
// OpenTransport-has-a-new-but-platform.h-#defs-new-to-something-nonstandard
// issue, so we need to pre-include OT here...
#include <OpenTransport.h>
#endif

#include "platformMacCarb/platformMacCarb.h"
#include "platformMacCarb/platformGL.h"
#include "platform/platform.h"
#include "platform/platformVideo.h"
#include "platformMacCarb/maccarbOGLVideo.h"
#include "platform/event.h"
#include "console/console.h"
#include "platformMacCarb/maccarbConsole.h"
#include "platform/platformInput.h"
//#include "platformMacCarb/maccarbInput.h"
#include "platform/gameInterface.h"
#include "math/mRandom.h"
#include "core/fileStream.h"
#include "game/resource.h"
#include "platformMacCarb/maccarbFileio.h"
#include "core/fileio.h"
#include "platform/platform.h"

//-------------------------------------- Mac stuff

#if defined(TORQUE_OS_MAC_CARB)  //&& (CARBON_VERSION>=0x0120) // !!!TBD -- ASSUMES WE'RE ALWAYS RECENT CARBON LIB.

// !!!!TBD these could get eliminated if we're stable on the new event mgmt & event loop systems.
#define TARG_MACCARB_EVENTS          1
#define CARBEVENTS_RAEL              (1 && TARG_MACCARB_EVENTS)

static MRandomLCG sgPlatRandom;

bool carbonEventsReady = false;
bool carbEventsRAEL = false;

// for OSX window layering control.
//#include "CGWindowLevel.h" // only if we reference the consts or funcs directly...
#if defined(TORQUE_OS_MAC_OSX)
#include <Carbon/Carbon.h>
#include <DrawSprocket/DrawSprocket.h>
#else
#include <MacWindows.h>
#include <DrawSprocket.h>
#endif
WindowGroupRef masterGroup = NULL;

#else // OS8-legacy-stuff.

#include <DrawSprocket.h>

#endif // MAC_CARB ifdef

#include <AGL/agl.h>
#include <stdio.h>

#if USE_SIOUX
#include <SIOUX.h>
#include <Gestalt.h>
#endif

//-------------------------------------- Resource Includes
#include "dgl/gBitmap.h"
#include "dgl/gFont.h"

extern void createFontInit();
extern void createFontShutdown();

void installCarbonEventHandlers(void);
void removeCarbonEventHandlers(void);

EventHandlerRef gWinEventHandlerRef, gAppEventHandlerRef, gTextEventHandlerRef;

bool gWindowCreated = false;

#if 0
char c;
#define TEST_STAGE(instr) printf(">> %s\n", instr);  c = getchar();
#else
#define TEST_STAGE(s)
#endif


MacCarbPlatState platState;

MacCarbPlatState::MacCarbPlatState()
{
   hDisplay    = NULL;
   appWindow   = NULL;
   
   quit      = false;

   ctx         = NULL;

   // start with something reasonable.
   desktopBitsPixel = 16;
   desktopWidth = 1024;
   desktopHeight = 768;

   osVersion = 0;
   osX = false;
   
   dStrcpy(appWindowTitle, "MacOS Torque Game Engine");
}

// THIS IS A GLOBAL! MUST BE CHANGED WHEN AFFECTING CURSOR VISIBILITY!
int cursorHidden = 0;

static bool windowLocked = false;

static U8 keyboardState[256];
static bool mouseButtonState[8];
static bool capsLockDown = false;
static S32 modifierKeys = 0;
static bool windowActive = true;

static Point2I lastCursorPos(0,0);
static Point2I windowSize;
//static bool sgDoubleByteEnabled = false;

static const char *getKeyName(S32 vkCode);

#define TICKS_FRONT      0L
#define TICKS_FRONT_X    1L
#define TICKS_BACK       Platform::getBackgroundSleepTime()
#define TICKS_BACK_X     Platform::getBackgroundSleepTime()
static bool gBackgrounded = false;
static long gSleepTicks = 1L; // start with something safe...

//--------------------------------------
static const char *getMessageName(S32 msg)
{
   switch(msg)
   {
//      case WM_KEYDOWN:
//         return "WM_KEYDOWN";
//      case WM_KEYUP:
//         return "WM_KEYUP";
//      case WM_SYSKEYUP:
//         return "WM_SYSKEYUP";
//      case WM_SYSKEYDOWN:
//         return "WM_SYSKEYDOWN";
      default:
         return "Unknown!!";
   }
}

#if defined(TORQUE_OS_MAC_CARB)
//--------------------------------------
// helper function to load fnptrs on OSX
#include <CFBundle.h>
#include <Folders.h>

//-------------------------------------------------------------------------------
// Function name:  LoadPrivateFrameworksBundle
// Summary:        Looks in the application's Frameworks folder for a framework,
//                  and loads it if it finds it.
//                  Adpoted from a forum post by David 'FenrirWolf' Grace.
//-------------------------------------------------------------------------------
bool LoadPrivateFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr) {
	// Looks in the application bundle for a framework, and loads it if it finds it.
	
	CFURLRef   privFrameworksURL, bundleURL;
	if(!( privFrameworksURL = CFBundleCopyPrivateFrameworksURL( CFBundleGetMainBundle() )) ) {
		return false;
	}

	
	if(!( bundleURL = CFURLCreateCopyAppendingPathComponent(NULL, privFrameworksURL, framework, false)) ) {
		CFRelease(privFrameworksURL);
		return false;
	}
	
    *bundlePtr = CFBundleCreate(NULL, bundleURL);
	if (*bundlePtr && CFBundleLoadExecutable( *bundlePtr ) ) {
		//found it under the apps private framework
		CFRelease(privFrameworksURL);
		CFRelease(bundleURL);
		return true;
	}
    
    CFRelease(privFrameworksURL);
    CFRelease(bundleURL);
    if(*bundlePtr != NULL)
        CFRelease(*bundlePtr);
    return false;
}


// this function was adopted from Apple "CallMachOFramework" sample application
OSStatus LoadFrameworkBundle(CFStringRef framework, CFBundleRef *bundlePtr)
{
	const int	numLocs = 5;
	int maxLocs = numLocs - ((platState.osX)?0:1);
	short		vols[numLocs] = {kOnAppropriateDisk,
								kOnAppropriateDisk,
								kOnAppropriateDisk,
								kLocalDomain,
								kLocalDomain};
	OSType		folderType[numLocs] = {kPrivateFrameworksFolderType,
										kFrameworksFolderType,
										kApplicationSupportFolderType,
										kFrameworksFolderType,
										kDomainLibraryFolderType}; // OSX only searchpath.
	OSStatus    err;
	FSRef       frameworksFolderRef;
	CFURLRef   baseURL;
	CFURLRef   bundleURL;

	if (bundlePtr==NULL) return(-1);

	*bundlePtr = NULL;

    // Look in the application's Frameworks folder before looking in the system
	if( LoadPrivateFrameworkBundle(framework, bundlePtr) )
        return noErr ; // Yay!  We found it, so return with no error..
	// Otherwise, fall through to Torques usual bundle load logic
		

	baseURL = NULL;
	bundleURL = NULL;

	for (int i = 0; i<maxLocs; i++)
	{
	   err = FSFindFolder(vols[i], folderType[i], true, &frameworksFolderRef);
	   if (err == noErr) {
	      baseURL = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &frameworksFolderRef);
	      if (baseURL == NULL) {
	         err = coreFoundationUnknownErr;
	      }
	   }
	   if (err == noErr) {
	      bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, framework, false);
	      if (bundleURL == NULL) {
	         err = coreFoundationUnknownErr;
	      }
	   }
	   if (err == noErr) {
	      *bundlePtr = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL);
	      if (*bundlePtr == NULL) {
	         err = coreFoundationUnknownErr;
	      }
	   }
	   if (err == noErr) {
	      if ( ! CFBundleLoadExecutable( *bundlePtr ) ) {
	         err = coreFoundationUnknownErr;
	      }
	      else // GOT IT!
	      	break;
	   }
	}
	
   // Clean up.
   if (err != noErr && *bundlePtr != NULL)
   {
      CFRelease(*bundlePtr);
      *bundlePtr = NULL;
   }
   if (bundleURL != NULL)
      CFRelease(bundleURL);
   if (baseURL != NULL)
      CFRelease(baseURL);
   
   return err;
}


//--------------------------------------
// typedefs for the fns we need:
#include <CGDirectDisplay.h>
typedef CGDisplayErr (*CGGDWPPtr) (CGPoint p, CGDisplayCount m, CGDirectDisplayID *d, CGDisplayCount *c);
typedef CGRect (*CGDBPtr) (CGDirectDisplayID d);
typedef CGDisplayErr (*CGDMCTPPtr) (CGDirectDisplayID d, CGPoint p);

static CGGDWPPtr cgddGetDisplay = NULL;
static CGDBPtr cgddBounds = NULL;
static CGDMCTPPtr cgddTeleportMouse = NULL;

static OSStatus LoadCGDDFunctions()
{
   CFBundleRef cgBundle;
   OSStatus err = cfragNoSymbolErr;

   if (!platState.osX) return(err);

//   err = LoadFrameworkBundle(CFSTR("CoreGraphics.framework"), &cgBundle);
   err = LoadFrameworkBundle(CFSTR("ApplicationServices.framework"), &cgBundle);
   if (err!=noErr) return(err);
   
   cgddGetDisplay = (CGGDWPPtr) CFBundleGetFunctionPointerForName( cgBundle, CFSTR("CGGetDisplaysWithPoint") );
   if (cgddGetDisplay == NULL)
      err = cfragNoSymbolErr;
   cgddBounds = (CGDBPtr) CFBundleGetFunctionPointerForName( cgBundle, CFSTR("CGDisplayBounds") );
   if (cgddBounds == NULL)
      err = cfragNoSymbolErr;
   cgddTeleportMouse = (CGDMCTPPtr) CFBundleGetFunctionPointerForName( cgBundle, CFSTR("CGDisplayMoveCursorToPoint") );
   if (cgddTeleportMouse == NULL)
      err = cfragNoSymbolErr;
   
   return(err);
}
#endif //TARG_MACCARB


void Platform::AlertOK(const char *windowTitle, const char *message)
{
/*
   S16 hit;
   Str255 title, desc;
   str2p(windowTitle, title);
   str2p(message, desc);

   Input::deactivate();

   StandardAlert(0, title, desc, NULL, &hit);
*/
   S16 hit;
   AlertStdAlertParamRec param;
   Str255 title, desc;
   str2p(windowTitle, title);
   str2p(message, desc);
   param.movable = true;
   param.helpButton = false;
   param.filterProc = NULL;
   param.defaultText = (StringPtr)kAlertDefaultOKText;
   param.cancelText = NULL;
   param.otherText = NULL;
   param.defaultButton = kAlertStdAlertOKButton;
   param.cancelButton = 0;
   param.position = kWindowDefaultPosition;
   // BUG: when in full screen, the alert doesnt show. The best fix for this is new mac platf.
   if( Video::isFullScreen()) {
      Con::printf("Cannot display alerts in full screen mode. Dumping message to console...");
      Con::errorf("%s, %s",windowTitle,message);
      return;
   }
   
   removeCarbonEventHandlers();                 /// stop capturing all events
   ShowCursor();                                /// give user a mouse cursor with which to click buttons
   StandardAlert(0, title, desc, &param, &hit); /// show the alert box 
   installCarbonEventHandlers();                /// capture events again.
   HideCursor();                                /// hide system cursor, so we use torque's cursor again
   return; // (hit==kAlertStdAlertOKButton);
}

bool Platform::AlertOKCancel(const char *windowTitle, const char *message)
{
   S16 hit;
   AlertStdAlertParamRec param;
   Str255 title, desc;
   str2p(windowTitle, title);
   str2p(message, desc);
   param.movable = true;
   param.helpButton = false;
   param.filterProc = NULL;
   param.defaultText = (StringPtr)kAlertDefaultOKText;
   param.cancelText = (StringPtr)kAlertDefaultCancelText;
   param.otherText = NULL;
   param.defaultButton = kAlertStdAlertOKButton;
   param.cancelButton = kAlertStdAlertCancelButton;
   param.position = kWindowDefaultPosition;
   // BUG: when in full screen, the alert doesnt show. The best fix for this is new mac platf.
   if( Video::isFullScreen()) {
      Con::printf("Cannot display alerts in full screen mode. Dumping message to console...");
      Con::errorf("%s, %s",windowTitle,message);
      return true; // always return "OK".
   }
   
   removeCarbonEventHandlers();                 /// stop capturing all events
   ShowCursor();                                /// give user a mouse cursor with which to click buttons
   StandardAlert(0, title, desc, &param, &hit); /// show the alert box
   installCarbonEventHandlers();                /// capture events again.
   HideCursor();                                /// hide system cursor, so we use torque's cursor again
   return (hit==kAlertStdAlertOKButton);
}

bool Platform::AlertRetry(const char *windowTitle, const char *message)
{
   S16 hit;
   AlertStdAlertParamRec param;
   Str255 title, desc;
   Str255 retryStr;
   str2p(windowTitle, title);
   str2p(message, desc);
   str2p("Retry", retryStr);
   param.movable = true;
   param.helpButton = false;
   param.filterProc = NULL;
   param.defaultText = retryStr;
   param.cancelText = (StringPtr)kAlertDefaultCancelText;
   param.otherText = NULL;
   param.defaultButton = kAlertStdAlertOKButton;
   param.cancelButton = kAlertStdAlertCancelButton;
   param.position = kWindowDefaultPosition;
   // BUG: when in full screen, the alert doesnt show. The best fix for this is new mac platf.
   if( Video::isFullScreen()) {
      Con::printf("Cannot display alerts in full screen mode. Dumping message to console...");
      Con::errorf("%s, %s",windowTitle,message);
      return false; // always return 'cancel', as asserts use alertRetry, and constantly retrying would be bad.
   }
   
   removeCarbonEventHandlers();                 /// stop capturing all events
   ShowCursor();                                /// give user a mouse cursor with which to click buttons
   StandardAlert(0, title, desc, &param, &hit); /// show the alert box
   installCarbonEventHandlers();                /// capture events again.
   HideCursor();                                /// hide system cursor, so we use torque's cursor again
   return (hit==kAlertStdAlertOKButton);
}

//--------------------------------------
static void InitInput()
{
   dMemset( keyboardState, 0, 256 );
   dMemset( mouseButtonState, 0, sizeof( mouseButtonState ) );

   if (platState.osX)
   {
      OSStatus err = LoadCGDDFunctions();
   }
}

static Point& ClientToScreen( WindowPtr wnd, Point pt )
{
   static Point screen;
   screen = pt;
   
   GrafPtr savePort;
   GetPort( &savePort );
   SetPortWindowPort(platState.appWindow);
   LocalToGlobal( &screen );
   SetPort( savePort );
   
   return screen;
}


void GetWindowRect( WindowPtr wnd, RectI *pRect )
{
   // note - I should probably add a check for title bar, and borders to simulate Windows completely.
   if ( pRect && wnd ) 
   {
      GrafPtr port;
      Rect r;
      GetPort( &port );
      SetPortWindowPort(wnd);
      GetWindowPortBounds(wnd, &r);
      SetPort( port );
      
      pRect->point.x  = r.left;
      pRect->point.y  = r.top;
      pRect->extent.x = r.right - r.left;
      pRect->extent.y = r.bottom - r.top;
   } 
}


static void RecenterCapturedMouse(void)
{
   if (!platState.appWindow || !windowLocked)
      return;
      
   Rect r;
   Point wndCenter;
   GrafPtr savePort;
   GetPort( &savePort );
   SetPortWindowPort(platState.appWindow);
   GetWindowPortBounds(platState.appWindow, &r);
   wndCenter.h = r.left + (r.right-r.left)>>1;
   wndCenter.v = r.top + (r.bottom-r.top)>>1;
   LocalToGlobal( &wndCenter );

   if (!platState.osX)
   {
   }
#if defined(TORQUE_OS_MAC_CARB)
   else // on OSX, we use CGDD functions.
   if (cgddGetDisplay!=NULL) // then we have the funcs we need.
   {
      CGDirectDisplayID cgdid;
      CGDisplayCount cgdc;
      CGPoint cgp;
      cgp.x =  wndCenter.h;
      cgp.y =  wndCenter.v;
      cgddGetDisplay(cgp, 1, &cgdid, &cgdc);
      if (cgdc) // had better be non-zero!!!
      {
         CGRect cgr = cgddBounds(cgdid);
         cgp.x =  wndCenter.h - cgr.origin.x;
         cgp.y =  wndCenter.v - cgr.origin.y;
         cgddTeleportMouse(cgdid, cgp);
      }
   }
#endif
   
   SetPort( savePort );
}


static void GetMousePos(Point *pt)
{
   GrafPtr savePort;
   GetPort( &savePort );
   SetPortWindowPort( platState.appWindow );
   GetMouse(pt);
   SetPort( savePort );
}


//--------------------------------------
static bool HandleUpdate(WindowPtr w)
{
   if (w && w == platState.appWindow)
   {
#if TARG_MACCARB_EVENTS
      if (!carbonEventsReady)
#endif
      BeginUpdate(w);
      Game->refreshWindow();
#if TARG_MACCARB_EVENTS
      if (!carbonEventsReady)
#endif
      EndUpdate(w);
      return(true);
   }
   
   return(false);
}


//--------------------------------------
static void HandleActivate(WindowPtr w, bool winActive, bool appActive)
{
   if (w && w==platState.appWindow)
   {
      if (appActive)
      {
         ShowWindow(w);
         SelectWindow(w);
         BringToFront(w);
         
         cursorHidden = 0;
         Input::activate();
         
//         Video::reactivate();
      }
      else
      {
//         Video::deactivate();
         
         // if any input captured -- release all input states so we don't errantly keep them locked... 
         Input::deactivate();
         InitCursor(); // reset cursor state.
         cursorHidden = 0;
      }
      
      if (winActive)
      {
         ShowWindow(w);
         SelectWindow(w);
         BringToFront(w);

         cursorHidden = 0;
         Input::activate();
      }
      else
      {
         // if any input captured -- release all input states so we don't errantly keep them locked... 
         Input::deactivate();
         InitCursor(); // reset cursor state.
         cursorHidden = 0;
      }

      HandleUpdate(w);
   }
}

//--------------------------------------
void Platform::setWindowLocked(bool locked)
{
   bool noChange = (windowLocked==locked);
   
   if (!noChange)
   {
      windowLocked = locked;
   
      // do anything needed on state change.  like mouse recentering...
      if (windowLocked)
      {
         // reset the mouse cursor to center
         RecenterCapturedMouse();
         
         // need to do this for sanity.
         //HideMenuBar();
			///tbd this needs to funnel, so fullscreen & windowed share state tracking...
      }
      else
      {
         //ShowMenuBar();
			///tbd this needs to funnel, so fullscreen & windowed share state tracking...
      }
//      setMouseClipping();
   }
}


#if TARG_MACCARB_EVENTS
//--------------------------------------
// the following are the two event handlers
// we custom install.
//--------------------------------------

static bool inWinHandlerAlready = false;

//--------------------------------------
pascal OSStatus DoWinCarbonEventHandling(EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
{
   if (inWinHandlerAlready)
      return(eventNotHandledErr);

inWinHandlerAlready = true;

   OSStatus result = noErr; // Function result
   
   UInt32 eventClass = GetEventClass(theEvent);
   UInt32 eventKind = GetEventKind(theEvent);
   
   InputEvent vev;

   // clear the event value. make sure to not clear the Event initialized fields!!!
   dMemset(((char*)&vev)+sizeof(Event), 0, sizeof(vev)-sizeof(Event));
   
   /* Your preprocessing here */

   // Do preprocessing
/*
   if (eventClass==kEventClassMouse && eventKind==kEventMouseDown)
      result = -1;
   if (eventClass==kEventClassKeyboard && eventKind==kEventRawKeyDown)
      result = -2;
*/

   // we used to only process if the next handler up the chain handled the event, or did not handle it.
   // we would only skip handling event if there was some error.
   // propogation has been moved down below.
   
   /* Your postprocessing here */
   result = noErr; // clear result state.
   UInt32 keyMods = 0;
   GetEventParameter (theEvent, kEventParamKeyModifiers, typeUInt32,
                     NULL, sizeof(UInt32), NULL, &keyMods);
   
   modifierKeys = 0;
   if (keyMods & shiftKey)          modifierKeys |= SI_LSHIFT;
   if (keyMods & rightShiftKey)     modifierKeys |= SI_RSHIFT;
   if (keyMods & cmdKey)            modifierKeys |= SI_LALT;
   if (keyMods & optionKey)         modifierKeys |= SI_MAC_LOPT;
   if (keyMods & rightOptionKey)    modifierKeys |= SI_MAC_ROPT;
   if (keyMods & controlKey)        modifierKeys |= SI_LCTRL;
   if (keyMods & rightControlKey)   modifierKeys |= SI_RCTRL;

   // Do postprocessing
   switch(eventClass)
   {
      case kEventClassKeyboard:
      {
         bool makeBeforeBreak = false;
         UInt32   keyCode = 0;
         char     keyChar = 0;
         
         GetEventParameter (theEvent, kEventParamKeyCode, typeUInt32,
                           NULL, sizeof(UInt32), NULL, &keyCode);
         GetEventParameter (theEvent, kEventParamKeyMacCharCodes, typeChar,
                           NULL, sizeof(char), NULL, &keyChar);

         switch(eventKind)
         {
            case kEventRawKeyModifiersChanged:
               break; // until we figure out just what this does...
               
            case kEventRawKeyDown:
            case kEventRawKeyUp:
            case kEventRawKeyRepeat:
            {
               vev.deviceType = KeyboardDeviceType;
               vev.objType    = SI_KEY;
               vev.objInst    = TranslateOSKeyCode(keyCode);
               vev.modifier   = modifierKeys;
               vev.ascii      = 0; 
                                 
               switch(eventKind)
               {
                  case kEventRawKeyDown:
                     vev.action = SI_MAKE;
                     vev.fValue = 1.0f;
                     keyboardState[keyCode] = 1; // track state.
                     break;
                  case kEventRawKeyUp:
                     vev.action = SI_BREAK;
                     vev.fValue = 0.0f;
                     keyboardState[keyCode] = 0; // track state.
                     break;
                  case kEventRawKeyRepeat:
                     vev.action = SI_REPEAT;
                     vev.fValue = 1.0f;
                     keyboardState[keyCode] = 2; // track state.
                     break;
                  case kEventRawKeyModifiersChanged:
                     break;
                  default:
                     break;
               }   

            // HACK HACK HACK
            // directly check for command-Q to force exit immediately!!!!!!TBD
            if ((vev.objInst == KEY_Q) && (keyMods & cmdKey))
               Platform::postQuitMessage(0);

               Game->postEvent(vev);

               break;
            }

            default:
               result = eventNotHandledErr;
               break;
         }
         
         break;
      }

      case kEventClassMouse:
      {
         switch(eventKind)
         {
            case kEventMouseDown:
            case kEventMouseUp:
            {
               EventMouseButton whatButton;
               GetEventParameter (theEvent, kEventParamMouseButton, typeMouseButton,
                                  NULL, sizeof(EventMouseButton), NULL, &whatButton);

               vev.deviceType = MouseDeviceType;
               vev.objType    = SI_BUTTON;
               vev.objInst    = KEY_BUTTON0 + whatButton - 1; // we assume the KEY_BUTTON values are in order, in seq.
               vev.modifier   = modifierKeys;
               vev.ascii      = 0;
               vev.action     = (eventKind==kEventMouseDown)?SI_MAKE:SI_BREAK;
               vev.fValue     = (eventKind==kEventMouseDown)?1.0:0.0;
               Game->postEvent(vev);
               mouseButtonState[whatButton-1] = (eventKind==kEventMouseDown)?1:0;
               break;
            }

            case kEventMouseMoved:
            case kEventMouseDragged:
            {
               GrafPtr savePort;
               GetPort( &savePort );

               Point where;
               GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint,
                                  NULL, sizeof(Point), NULL, &where);
               
               if (platState.appWindow)
               {
                  Rect r;
                  
                  // gee, almost forgot about this -- value is global, we want it window-local.
                  SetPortWindowPort(platState.appWindow);
                  GlobalToLocal(&where);
                  GetWindowPortBounds(platState.appWindow, &r);
                  SetPort(savePort);
               
                  // if mouse is in our window, make sure it is hidden.  if not, it should be visible.
                  bool inWindow = PtInRect(where, &r);
                  if (cursorHidden && !inWindow)
                  {
                     ShowCursor();
                     cursorHidden = 0;
                  }
                  else
                  if (!cursorHidden && inWindow)
                  {
                     HideCursor();
                     cursorHidden = 1;
                  }
               }

               // this is a hack workaround to manage the fact that the game wants delta values...
               static bool reset = true;
               static Point lastMouseLoc = {-11,-11}; // something unlikely...
               if (windowLocked && !platState.osX)
               if (!windowActive || gBackgrounded) //!!!!TBD windowActive/Locked should go false if bg.
               {
                  reset = true;
                  break; // out of this case.
               }

               static int wasLocked = 0;
               if (!windowLocked)
               { // then we want the raw, global mouse position.
                  MouseMoveEvent mme;
                  mme.xPos = where.h;     // horizontal position of cursor 
                  mme.yPos = where.v;     // vertical position of cursor 
                  mme.modifier = modifierKeys;
                  Game->postEvent(mme);
                  // if we care, we can check locked state flipping back.
                  // for now, just set flag.
                  wasLocked = 0;
               }
               else
               {
                  vev.deviceType = MouseDeviceType;
                  vev.objInst    = 0;
                  vev.modifier   = modifierKeys;
                  vev.ascii      = 0;
                  vev.action     = SI_MOVE;

#if defined(TORQUE_OS_MAC_OSX)
                  // we don't actually use the event data.
                  // we grab the raw delta from coregraphics.
                  CGMouseDelta mdx, mdy;
                  CGGetLastMouseDelta(&mdx, &mdy);
#else
                  // HACK for input control in-game when CFM on X, or when ISp temp disabled.
                  // There needs to be Input:: takeover of user input
                  // when the window is locked (gameplay)
                  int mdx, mdy;
                  if (platState.osX)
                  { // try to use carbon system for retrieving delta...
                     GetEventParameter (theEvent, kEventParamMouseDelta, typeQDPoint,
                                        NULL, sizeof(Point), NULL, &where);
                     mdx = where.h;
                     mdy = where.v;
                  }
                  else
                  { // try to determine delta ourselves, and not use carbon system...
                     // where already contains curr position...
                     if (reset)
                     {
                        reset = false;
                        lastMouseLoc = where;
                        break; // this case.
                     }
                  
                     mdx = where.h - lastMouseLoc.h;
                     mdy = where.v - lastMouseLoc.v;
                     lastMouseLoc = where;
                  }
#endif

                  if (wasLocked>1) // ignore first two events, so we skip errant behaviors...
                  { // post the event(s), possibly clamped a bit...
                     const int MAX_MOUSE_MOVE = 256;
                     if (mdx)
                     {
                        if (mdx > MAX_MOUSE_MOVE)
                           mdx = MAX_MOUSE_MOVE;
                        else if (mdx < -MAX_MOUSE_MOVE)
                           mdx = -MAX_MOUSE_MOVE;
                        vev.objType    = SI_XAXIS;
                        vev.fValue     = F32(mdx);
                        Game->postEvent(vev);
                     }
                     if (mdy)
                     {
                        if (mdy > MAX_MOUSE_MOVE)
                           mdy = MAX_MOUSE_MOVE;
                        else if (mdy < -MAX_MOUSE_MOVE)
                           mdy = -MAX_MOUSE_MOVE;
                        vev.objType    = SI_YAXIS;
                        vev.fValue     = F32(mdy);
                        Game->postEvent(vev);
                     }
                  }
                  else
                     wasLocked++; // else drop the events ON THE FLOOR.
                  
                  // reset the mouse cursor to center
                  RecenterCapturedMouse();
               }

               break;
            }

            case kEventMouseWheelMoved:
            {
               long dWheel = 0;
               GetEventParameter (theEvent, kEventParamMouseWheelDelta, typeLongInteger,
                                  NULL, sizeof(long), NULL, &dWheel);

               vev.deviceType = MouseDeviceType;
               vev.objType    = SI_ZAXIS;
               vev.objInst    = 0;
               vev.modifier   = 0; 
               vev.ascii      = 0; 
               vev.action     = SI_MOVE;
               vev.fValue     = dWheel; // !!!!TBD -- multiplication factor!!!!????
               Game->postEvent(vev);

               break;
            }

            default:
               result = eventNotHandledErr;
               break;
         }
         break;
      }

      case kEventClassWindow:
      {
         WindowRef theWind;
         GetEventParameter (theEvent, kEventParamDirectObject, typeWindowRef,
                             NULL, sizeof(WindowRef), NULL, &theWind);

         switch(eventKind)
         {
            case kEventWindowDrawContent:
            {
               // !!!!TBD.  Do we ned to bother checking theWind == platState.appWindow?
               Game->refreshWindow();
               break;
            }

            case kEventWindowActivated:
            case kEventWindowDeactivated:
            {
               // !!!!TBD.  Do we ned to bother checking theWind == platState.appWindow?
               HandleActivate(theWind, eventKind==kEventWindowActivated, !gBackgrounded);
               Game->refreshWindow();
               // mark that we didn't handle, so hopefully someone else will do the right thing.
               result = eventNotHandledErr;
               break;
            }

            default:
               result = eventNotHandledErr;
               break;
         }
         
         break;
      }

      default:
         result = eventNotHandledErr;
         break;
   }
   

#define PROPAGATE_EVENTS      1
#if PROPAGATE_EVENTS // whether to propagate...
   // Now propagate the event to the next handler (in this case the standard window handler)
   if (nextHandler)
   {
      result = CallNextEventHandler (nextHandler, theEvent);
   }
#endif


inWinHandlerAlready = false; // ending.

   return result; // Report result
}


//--------------------------------------
pascal OSStatus DoAppCarbonEventHandling(EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
{
   OSStatus result = noErr; // Function result
   
   UInt32 eventClass = GetEventClass(theEvent);
   UInt32 eventKind = GetEventKind(theEvent);
   
   InputEvent vev;

   // clear the event value. make sure to not clear the Event initialized fields!!!
   dMemset(((char*)&vev)+sizeof(Event), 0, sizeof(vev)-sizeof(Event));
   
   /* Your preprocessing here */

#if PROPAGATE_EVENTS // whether to propagate...
   // Now propagate the event to the next handler (in this case the standard window handler)
   if (nextHandler)
      result = CallNextEventHandler (nextHandler, theEvent);
#endif
   if (result == noErr
   ||  result == eventNotHandledErr) // Did it succeed or was unhandled?
   {
      /* Your postprocessing here */
      result = noErr; // clear result state.

      // Do postprocessing
      switch(eventClass)
      {
         case kEventClassAppleEvent:
         {
            AEEventID aeType;
            GetEventParameter (theEvent, kEventParamAEEventID, typeType,
                                NULL, sizeof(OSType), NULL, &aeType);

            switch(aeType)
            {
               case kAEQuitApplication:
               {
                  Platform::postQuitMessage(0);
                  break;
               }

               default:
                  result = eventNotHandledErr;
 //                 AEProcessAppleEvent(&msg?????);
                  break;
            }
            
            break;
         }

         case kEventClassApplication:
         {
            switch(eventKind)
            {
               case kEventAppQuit:
               {
                  // !!!!!TBD -- we assume this only happens AFTER we posted a quit event...
                  break;
               }

               case kEventAppActivated:
               case kEventAppDeactivated:
               {
                  bool activating = (eventKind==kEventAppActivated);
                  
                  HandleActivate(platState.appWindow, activating, activating);
                  gBackgrounded = !activating;
                  if (gBackgrounded)
                     gSleepTicks = TICKS_BACK_X;
                  else
                     gSleepTicks = TICKS_FRONT_X;
/*                  
                  Cursor arrow; 
                  GetQDGlobalsArrow(&arrow);
                  if (gBackgrounded)   // just suspended
                     SetCursor(&arrow);
                  else                  // just resumed
                     SetCursor(&arrow);
*/                  
                  // mark it so that others will try to 'do the right thing' for us.
                  result = eventNotHandledErr;
                  
                  break;
               }

               default:
                  result = eventNotHandledErr;
                  break;
            }
            
            break;
         }
         
         case kEventClassKeyboard:
         {
            switch(eventKind)
            {
               case kEventRawKeyModifiersChanged: // until we figure out just what this does...
               case kEventRawKeyDown:
               case kEventRawKeyUp:
               case kEventRawKeyRepeat:
               {
                  // HACK HACK HACK HACK
                  // this should really be dispatched through the right
                  // dispatching mechanism to the main window...
                  if (!inWinHandlerAlready)
                     result = DoWinCarbonEventHandling(NULL, theEvent, userData);
                  break;
               }

               default:
                  result = eventNotHandledErr;
                  break;
            }
            break;
         }

         case kEventClassMouse:
         {
            switch(eventKind)
            {
               case kEventMouseDown:
               case kEventMouseUp:
               case kEventMouseMoved:
               case kEventMouseDragged:
               case kEventMouseWheelMoved:
               {
                  // HACK HACK HACK HACK
                  // this should really be dispatched through the right
                  // dispatching mechanism to the main window...
                  if (!inWinHandlerAlready)
                     result = DoWinCarbonEventHandling(NULL, theEvent, userData);
                  break;
               }

               default:
                  result = eventNotHandledErr;
                  break;
            }
            break;
         }

         default:
            result = eventNotHandledErr;
            break;
      }

   }

   return result; // Report result
}
//--------------------------------------
#endif // targ_maccarb_events

//--------------------------------------
static Point lastPos = {-11,-11}; // something unlikely...
static void CheckCursorPos()
{
   static bool reset = true;

   if (!windowActive || gBackgrounded) //!!!!TBD windowActive/Locked should go false if bg.
   {
      reset = true;
      return;
   }
   
   InputEvent event;
   Point mousePos;
   GetMousePos(&mousePos);

   if (!windowLocked)
   {
      // since we're in Poll mode, we need to post a mousemove event for the cursor to be updated.
      MouseMoveEvent mme;
      mme.xPos = mousePos.h;     // horizontal position of cursor 
      mme.yPos = mousePos.v;     // vertical position of cursor 
      mme.modifier = modifierKeys;
      Game->postEvent(mme);
   }
   else
   {
      if (reset)
         reset = false;
      else
      if (mousePos.h!=lastPos.h
      &&  mousePos.v!=lastPos.v) // mouse moved.
      {
         if(mousePos.h != lastPos.h)
         {
            event.deviceInst  = 0;
            event.deviceType  = MouseDeviceType;
            event.objType     = SI_XAXIS;
            event.objInst     = 0;
            event.action      = SI_MOVE;
            event.modifier    = modifierKeys;
            event.ascii       = 0;
            event.fValue      = F32(mousePos.h - lastPos.h);
            Game->postEvent(event);
//            Con::printf( "EVENT: Mouse move (%.1f, 0.0).\n", event.fValue );
         }

         if(mousePos.v != lastPos.v)
         {
            event.deviceInst  = 0;
            event.deviceType  = MouseDeviceType;
            event.objType     = SI_YAXIS;
            event.objInst     = 0;
            event.action      = SI_MOVE;
            event.modifier    = modifierKeys;
            event.ascii       = 0;
            event.fValue      = F32(mousePos.v - lastPos.v);
            Game->postEvent(event);
//           Con::printf( "EVENT: Mouse move (0.0, %.1f).\n", event.fValue );
         }

      }

      lastPos = mousePos; // copy over last position.
   }
}



#define WINDOW_RESTRICT_EVENTS      0

static void ProcessKeyboard( EventRecord &msg )
{
#if WINDOW_RESTRICT_EVENTS
   WindowPtr which;
   FindWindow( msg.where, &which );
   if (which != platState.appWindow)
      return;
#endif

#if ALLOW_MENU_PROCESSING
   unsigned char c;
   c = (msg.message & charCodeMask);
   if ((msg.modifiers & cmdKey) != 0)
   {
      AdjustMenus();
      HandleMenuKey(c, msg.modifiers);
   }
#endif
   
   InputEvent event;
   event.deviceInst  = 0;
   event.deviceType  = KeyboardDeviceType;
   event.objType     = SI_KEY;
   event.objInst     = TranslateOSKeyCode( (msg.message & keyCodeMask) >> 8 );
   event.ascii       = 0;

   switch(msg.what)
   {
      case keyDown:
         event.action = SI_MAKE;
         event.fValue = 1.0f;
         //Con::printf("keyDN ( %02x )", (msg.message & keyCodeMask) >> 8);
         break;
         
      case autoKey:
         event.action = SI_REPEAT;
         event.fValue = 1.0f;
         break;
         
      case keyUp:
         event.action = SI_BREAK;
         event.fValue = 0.0f;
         //Con::printf("keyUP ( %02x )", (msg.message & keyCodeMask) >> 8);   
         break;
   }   
   
   event.modifier = 0;
   if (msg.modifiers & shiftKey)          event.modifier |= SI_LSHIFT;
   if (msg.modifiers & rightShiftKey)     event.modifier |= SI_RSHIFT;
   if (msg.modifiers & cmdKey)            event.modifier |= SI_LALT;
   if (msg.modifiers & optionKey)         event.modifier |= SI_MAC_LOPT;
   if (msg.modifiers & rightOptionKey)    event.modifier |= SI_MAC_ROPT;
   if (msg.modifiers & controlKey)        event.modifier |= SI_LCTRL;
   if (msg.modifiers & rightControlKey)   event.modifier |= SI_RCTRL;

   // handle command-Q exit
   if ((event.objInst == KEY_Q) && (msg.modifiers & cmdKey))
      Platform::postQuitMessage(0);

   Game->postEvent(event);
}


static void ProcessMouse( EventRecord &msg )
{
   WindowPtr which;
   U16 where = FindWindow( msg.where, &which );
#if WINDOW_RESTRICT_EVENTS
   if (which != platState.appWindow)
      return;
#endif

   SelectWindow(platState.appWindow);
   
   // handle a little window maintence
   switch (where)
   {
#if !TARGET_API_MAC_CARBON
      case inSysWindow:
         SystemClick ( &msg, platState.appWindow );
         return;
#endif
      
      case inDrag:
      {
         RgnHandle rgn = GetGrayRgn();
         Rect r;
         GetRegionBounds(rgn, &r);
         SetPortWindowPort(platState.appWindow);
         DragWindow(platState.appWindow, msg.where, &r);
         if (platState.ctx)
            aglUpdateContext((AGLContext)platState.ctx);
         HandleUpdate(platState.appWindow);
         return;
      }   
         
      case inContent:
         // will handle below.
         break;

      default:
         return;
   }
   
   
   InputEvent event;
   event.deviceInst  = 0;
   event.deviceType  = MouseDeviceType;
   event.objType     = SI_BUTTON;
   event.objInst     = KEY_BUTTON0;      // always button 0 for now
   event.modifier    = 0;
   event.ascii       = 0;
   if (msg.what == mouseDown)
      event.action = SI_MAKE;
   else
      event.action = SI_BREAK;
   event.fValue = event.action==SI_MAKE?1.0:0.0;
   Game->postEvent(event);
}


//--------------------------------------
#define TICK_WAIT_FOR_WNE        4
static bool ProcessMessages()
{
   EventRecord msg;
   bool done = false;
   static U32 lastTick = 0;
   U32 newTick = TickCount();

   if (platState.quit) return false;

#if CARBEVENTS_RAEL
   if (platState.osX && carbEventsRAEL)
   {
      EventRef carbonEvent;
      EventTargetRef theTarget;
      OSStatus theErr;

      theTarget = GetEventDispatcherTarget();
      do
      {
         theErr = ReceiveNextEvent(0, NULL, kEventDurationNoWait, true, &carbonEvent);
         if (theErr == noErr && carbonEvent != NULL)
         {
            bool handled = false;

            // make a normal Mac event.
            // !!!!TBD

            // not sure if this is needed under OSX.
            // !!!!TBD.
            extern bool gDSpActive;
            if (gDSpActive)
            {
               // pass to DSp.
               Boolean dspdid;
               DSpProcessEvent(&msg, &dspdid);
               if (dspdid) handled = true;
            }

   // !!!!TBD
   //         if (!handled)
   //          handled = (gConsole && gConsole->handleEvent(&msg));
	
            if (!handled)
               theErr = SendEventToEventTarget(carbonEvent, theTarget);
            ReleaseEvent(carbonEvent);
         }
      }
      while (theErr == noErr);
   }
   else
#endif
   while(!done)
   {
      if (!windowLocked || platState.osX) // since WNE seems the only proper thing to do on X...
      {
         done = (false==WaitNextEvent(everyEvent, &msg, gSleepTicks, NULL));
      }
      else // windowLocked && !osx...
      {
         if (newTick-lastTick < TICK_WAIT_FOR_WNE)
            done = (false==GetNextEvent(everyEvent, &msg));
         else
            done = (false==WaitNextEvent(everyEvent, &msg, gSleepTicks, NULL));
         lastTick = newTick;
      }
      // not sure if this is needed under OSX.
      // !!!!TBD.
      extern bool gDSpActive;
      if (gDSpActive)
      {
         Boolean dspdid;
         DSpProcessEvent(&msg, &dspdid);
         if (dspdid) continue;
      }
      
      bool handled = (gConsole && gConsole->handleEvent(&msg));
      if (!handled)
      switch(msg.what)
      {
         case nullEvent:
            //AdjustCursor(msg.where, ((msg.modifiers&optionKey)!=0), cursorRgn);
            done = true;
            break;
             
         case keyDown:
//       case autoKey:
         case keyUp:
            ProcessKeyboard(msg);
            break;
            
          case mouseDown:
          case mouseUp:
             ProcessMouse(msg);
             break;
             
         case activateEvt:
            HandleActivate((WindowPtr)(msg.message), (msg.modifiers & activeFlag) != 0, !gBackgrounded);
            break;

          case updateEvt:
            HandleUpdate((WindowPtr)(msg.message));
             break;
          
          case osEvt:
          {
            switch ((unsigned long)(msg.message >> 24)) // osEvt msg is in the high byte.
            {
               case mouseMovedMessage: // this is it moved from the region passed to WNE
               {
//                AdjustCursor(msg.where, ((msg.modifiers&optionKey)!=0), cursorRgn);
                  break;
               }
               
               case suspendResumeMessage:
               {
                  gBackgrounded = (msg.message & resumeFlag) == 0;
                  HandleActivate(platState.appWindow, !gBackgrounded, !gBackgrounded);
                  if (gBackgrounded)
                     gSleepTicks = TICKS_BACK_X;
                  else
                     gSleepTicks = TICKS_FRONT_X;
                  
/*
                  Cursor arrow; 
                  GetQDGlobalsArrow(&arrow);
                  if (gBackgrounded)   // just suspended
                     SetCursor(&arrow);
                  else                  // just resumed
                     SetCursor(&arrow);
*/
                  break;
               }/* end case suspend/resume evt */
            }
            
             break;
          }
          
         case kHighLevelEvent:
         {
            // the type of message is stored in the where Point... so cast it
            U32 hlWhat = *((U32*)(&msg.where));   
            if ( hlWhat == kAEQuitApplication )
            {
               Platform::postQuitMessage(0);
               return false;
            }
            else 
               AEProcessAppleEvent(&msg);
            break;
         }
            
         default:
         //   Con::printf("%d %08x", msg.what, msg.what);
            break;
      }
      
#if TARG_MACCARB_EVENTS
      if (platState.osX) // then we one do one WNE per Process call.
         done = true;
#endif
   }
   
   return true;
}


//--------------------------------------
void Platform::process()
{
   extern bool gMouseActive;
   if (!Input::isActive() || !gMouseActive)
#if TARG_MACCARB_EVENTS
   if (!carbonEventsReady) // we don't poll mouse if we have CarbonEvents working...
#endif
      CheckCursorPos();

/*
#if 0//TARG_MACCARB_EVENTS
// the moment we activate this code block, we lose all base WNE handling,
// so we'd need to convert to using a carbon timer or something to process the main loop.
   if (carbonEventsReady)
   {
      RunApplicationEventLoop();
   }
   else
#endif
*/
   if(!ProcessMessages())
   {
      // generate a quit event
      Event quitEvent;
      quitEvent.type = QuitEventType;
      
      Game->postEvent(quitEvent);
   }


   Input::process();
}

extern U32 calculateCRC(void * buffer, S32 len, U32 crcVal );

#if defined(TORQUE_DEBUG) || defined(INTERNAL_RELEASE)
static U32 stubCRC = 0;
#else
static U32 stubCRC = 0xEA63F56C;
#endif

//--------------------------------------
/*
static void InitWindowClass()
{
   WNDCLASS wc;
   dMemset(&wc, 0, sizeof(wc));
   
   wc.style         = CS_OWNDC;
   wc.lpfnWndProc   = WindowProc;
   wc.cbClsExtra    = 0;
   wc.cbWndExtra    = 0;
   wc.hInstance     = winState.appInstance;
   wc.hIcon         = LoadIcon(winState.appInstance, MAKEINTRESOURCE(IDI_ICON2));
   wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
   wc.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
   wc.lpszMenuName  = 0;
   wc.lpszClassName = windowClassName;
   RegisterClass( &wc );
   
   // Curtain window class:
   wc.lpfnWndProc   = DefWindowProc;
   wc.hCursor       = NULL;
   wc.hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH);
   wc.lpszClassName = "Curtain";
   RegisterClass( &wc );
}
*/

//--------------------------------------
static void GetDesktopState()
{
   // desired display was already set inside Video::Init.
   //platState.hDisplay = GetMainDevice();
   
   Rect r = (*(platState.hDisplay))->gdRect;
   platState.desktopWidth = r.right - r.left;
   platState.desktopHeight = r.bottom - r.top;
   platState.desktopBitsPixel = (*(*(platState.hDisplay))->gdPMap)->pixelSize;
}



//--------------------------------------
WindowPtr CreateOpenGLWindow( GDHandle hDevice, U32 width, U32 height, bool fullScreen )
{
   WindowPtr w = NULL;
   int offset = 144; // some nice starting offset.
   bool noConsoleOffset = true;
   
   // this rect should really be based off the device coords... !!!!!TBD   
   Rect   rect, dRect;
   // note: OpenGL is expecting a window so it can enumerate the devices it spans, 
   // center window in our context's gdevice
   dRect = (**hDevice).gdRect;
   if (fullScreen || noConsoleOffset)
   {
      // not sure all the casting is needed, but...
      rect.top  = (short) (dRect.top + (dRect.bottom - dRect.top) / 2);        // h center
      rect.top  -= (height / 2);
      rect.left  = (short) (dRect.left + (dRect.right - dRect.left) / 2);   // v center
      rect.left  -= (width / 2);
      rect.right = (short) (rect.left + width);
      rect.bottom = (short) (rect.top + height);
   }
   else
   {
      // do an offset window, based on device bounds.
      SetRect( &rect, dRect.left+offset+48, dRect.top+offset, dRect.left+width+offset+48, dRect.top+height+offset);
   }
   
   if (platState.osX)
   {
      OSStatus stat;
      WindowAttributes windAttr = 0L;
      WindowClass windClass = kDocumentWindowClass;
      if (fullScreen)
      {
         windAttr |= kWindowNoShadowAttribute; // no shadow when fullscreen window.
         windClass = kAltPlainWindowClass;//kMovableAlertWindowClass; //kPlainWindowClass; //kOverlayWindowClass;
         if (windClass==kOverlayWindowClass)
            windAttr |= kWindowOpaqueForEventsAttribute;
      }
      else
         windAttr |= kWindowCollapseBoxAttribute;
      
      stat = CreateNewWindow(windClass, windAttr, &rect, &w);
      if (stat!=noErr || w==NULL)
         return(NULL); // !!!! ASSERT?????

      if (fullScreen)
      { // move the thing into the proper level, in front of the blanking window.
         // get blanking window level.
         // create a new group if ours doesn't already exist
         if (masterGroup==NULL)
         {
            WindowGroupAttributes grpAttr = 0L; // no special atts to start.
            stat = CreateWindowGroup(grpAttr, &masterGroup);
            // get the window's current group
            // TBD!!!!!
            // walk up the parent hierarchy, to find the topmost group.
            // TBD!!!!!
            // set the parent of our group to the topmost group.
            // TBD!!!!!
         }
         // place window in group
         stat = SetWindowGroup(w, masterGroup);
         if (stat!=noErr)
         {
         	int errCode1 = stat;
         }
         // set window level to one higher than blanking window.
         // for the moment, we'll hack this.
         stat = SetWindowGroupLevel(masterGroup, 1010); // above screen saver...
         if (stat!=noErr)
         {
         	int errCode2 = stat;
         }
//#define kCGScreenSaverWindowLevel   CGWindowLevelForKey(kCGScreenSaverWindowLevelKey)   /* 1000 */
//#define kCGMaximumWindowLevel       CGWindowLevelForKey(kCGMaximumWindowLevelKey)   /* LONG_MAX - kCGNumReservedWindowLevels */
      }
   }
   else
   { // old WMgr func.  this will become outdated...
      w = NewCWindow(NULL, 
                     &rect,                                                    // bounding rect
                     str2p(platState.appWindowTitle),                         // window title
                     false,                                                   // is visible
                     fullScreen?kWindowPlainDialogProc:kWindowDocumentProc,   // window type
                     (WindowPtr) -1L,                                          // top most window
                     false,                                                    // has a close box
                     0L);                                                      // reference constant
   }
   
   if (w != NULL)
   {
      GrafPtr savegp;
      RGBColor savergb;
      Rect bounds;
      const RGBColor rgbBlack = { 0x0000, 0x0000, 0x0000 };

      ShowWindow(w);
      SelectWindow(w);
      BringToFront(w);

      // paint back ground black before fade in to avoid white background flash
      GetPort (&savegp);
      SetPortWindowPort (w);
      GetForeColor (&savergb);
      RGBForeColor (&rgbBlack);
      GetWindowPortBounds (w, &bounds);
      PaintRect (&bounds);
      RGBForeColor (&savergb);      // ensure color is reset for proper blitting
      SetPort (savegp);
   }
   
   return(w);
}

//--------------------------------------
WindowPtr CreateCurtain( U32 width, U32 height )
{
   WindowPtr w=NULL;
/*   
   w =  CreateWindow( 
      "Curtain",
      "",
      ( WS_POPUP | WS_MAXIMIZE | WS_VISIBLE ),
      0, 0,
      width, height,
      NULL, NULL,
      winState.appInstance,
      NULL );
*/
   return(w);
}


/*
//--------------------------------------
void CreatePixelFormat( PIXELFORMATDESCRIPTOR *pPFD, S32 colorBits, S32 depthBits, S32 stencilBits, bool stereo )
{
   PIXELFORMATDESCRIPTOR src = 
   {
      sizeof(PIXELFORMATDESCRIPTOR),   // size of this pfd
      1,                      // version number
      PFD_DRAW_TO_WINDOW |    // support window
      PFD_SUPPORT_OPENGL |    // support OpenGL
      PFD_DOUBLEBUFFER,       // double buffered
      PFD_TYPE_RGBA,          // RGBA type
      colorBits,              // color depth
      0, 0, 0, 0, 0, 0,       // color bits ignored
      0,                      // no alpha buffer
      0,                      // shift bit ignored
      0,                      // no accumulation buffer
      0, 0, 0, 0,             // accum bits ignored
      depthBits,              // z-buffer   
      stencilBits,            // stencil buffer
      0,                      // no auxiliary buffer
      PFD_MAIN_PLANE,         // main layer
      0,                      // reserved
      0, 0, 0                 // layer masks ignored
    };

   if ( stereo )
   {
      //ri.Printf( PRINT_ALL, "...attempting to use stereo\n" );
      src.dwFlags |= PFD_STEREO;
      //glConfig.stereoEnabled = true;
   }
   else
   {
      //glConfig.stereoEnabled = qfalse;
   }
   *pPFD = src;
}

//--------------------------------------
enum { MAX_PFDS = 256 };

S32 ChooseBestPixelFormat(HDC hDC, PIXELFORMATDESCRIPTOR *pPFD)
{
   PIXELFORMATDESCRIPTOR pfds[MAX_PFDS+1];
   S32 i;
   S32 bestMatch = 0;
   
   S32 maxPFD = qwglDescribePixelFormat(hDC, 1, sizeof(PIXELFORMATDESCRIPTOR), &pfds[0]);
   if(maxPFD > MAX_PFDS)
      maxPFD = MAX_PFDS;

   bool accelerated = false;
   
   for(i = 1; i <= maxPFD; i++)
   {
      qwglDescribePixelFormat(hDC, i, sizeof(PIXELFORMATDESCRIPTOR), &pfds[i]);

      // make sure this has hardware acceleration:
      if ( ( pfds[i].dwFlags & PFD_GENERIC_FORMAT ) != 0 ) 
         continue;

      // verify pixel type
      if ( pfds[i].iPixelType != PFD_TYPE_RGBA )
         continue;

      // verify proper flags
      if ( ( ( pfds[i].dwFlags & pPFD->dwFlags ) & pPFD->dwFlags ) != pPFD->dwFlags ) 
         continue;

      accelerated = !(pfds[i].dwFlags & PFD_GENERIC_FORMAT);

      //
      // selection criteria (in order of priority):
      // 
      //  PFD_STEREO
      //  colorBits
      //  depthBits
      //  stencilBits
      //
      if ( bestMatch )
      {
         // check stereo
         if ( ( pfds[i].dwFlags & PFD_STEREO ) && ( !( pfds[bestMatch].dwFlags & PFD_STEREO ) ) && ( pPFD->dwFlags & PFD_STEREO ) )
         {
            bestMatch = i;
            continue;
         }
         
         if ( !( pfds[i].dwFlags & PFD_STEREO ) && ( pfds[bestMatch].dwFlags & PFD_STEREO ) && ( pPFD->dwFlags & PFD_STEREO ) )
         {
            bestMatch = i;
            continue;
         }

         // check color
         if ( pfds[bestMatch].cColorBits != pPFD->cColorBits )
         {
            // prefer perfect match
            if ( pfds[i].cColorBits == pPFD->cColorBits )
            {
               bestMatch = i;
               continue;
            }
            // otherwise if this PFD has more bits than our best, use it
            else if ( pfds[i].cColorBits > pfds[bestMatch].cColorBits )
            {
               bestMatch = i;
               continue;
            }
         }

         // check depth
         if ( pfds[bestMatch].cDepthBits != pPFD->cDepthBits )
         {
            // prefer perfect match
            if ( pfds[i].cDepthBits == pPFD->cDepthBits )
            {
               bestMatch = i;
               continue;
            }
            // otherwise if this PFD has more bits than our best, use it
            else if ( pfds[i].cDepthBits > pfds[bestMatch].cDepthBits )
            {
               bestMatch = i;
               continue;
            }
         }

         // check stencil
         if ( pfds[bestMatch].cStencilBits != pPFD->cStencilBits )
         {
            // prefer perfect match
            if ( pfds[i].cStencilBits == pPFD->cStencilBits )
            {
               bestMatch = i;
               continue;
            }
            // otherwise if this PFD has more bits than our best, use it
            else if ( ( pfds[i].cStencilBits > pfds[bestMatch].cStencilBits ) && 
                ( pPFD->cStencilBits > 0 ) )
            {
               bestMatch = i;
               continue;
            }
         }
      }
      else
      {
         bestMatch = i;
      }
   }
   
   if ( !bestMatch )
      return 0;

   else if ( pfds[bestMatch].dwFlags & PFD_GENERIC_ACCELERATED )
   {
      // MCD
   }
   else
   {
      // ICD
   }

   *pPFD = pfds[bestMatch];

   return bestMatch;
}
*/


//--------------------------------------
const Point2I &Platform::getWindowSize()
{
   return windowSize;
}


//--------------------------------------
void Platform::setWindowSize( U32 newWidth, U32 newHeight )
{
   windowSize.set( newWidth, newHeight );
}


//--------------------------------------
// !!!!!TBD!!!!! what should this do on the Mac.
void Platform::minimizeWindow()
{
}


//--------------------------------------
static void InitWindow(const Point2I &initialSize)
{
   windowSize = initialSize;   
}


//--------------------------------------
static void InitOpenGL()
{
   DisplayDevice::init();

   // Get the video settings from the prefs.
   const char* resString;
   U32 height, width, bpp;
   char *tempBuf, *s;
   bool fullScreen = Con::getBoolVariable( "$pref::Video::fullScreen" );
   // properly grab fullscreen vs windowed resolution.   
   if (fullScreen)
      resString = Con::getVariable( "$pref::Video::resolution" );
   else
      resString = Con::getVariable( "$pref::Video::windowedRes" );

   tempBuf = new char[dStrlen( resString ) + 1];
   dStrcpy( tempBuf, resString );

   s = dStrtok( tempBuf, " x\0" );
   width = ( s ? dAtoi( s ) : (windowSize.x > 0 ? windowSize.x : 640) );  //DAW: Added check for windowSize

   s = dStrtok( NULL, " x\0" );
   height = ( s ? dAtoi( s ) : (windowSize.y > 0 ? windowSize.y : 480) );  //DAW: Added check for windowSize

   if (fullScreen)
   {
      s = dStrtok( NULL, "\0" );
      bpp = ( s ? dAtoi( s ) : 16 );
   }
   else
      bpp = platState.desktopBitsPixel;

   delete [] tempBuf;

   if ( !Video::setDevice( Con::getVariable( "$pref::Video::displayDevice" ), width, height, bpp, fullScreen ) )
   {
      // Next, try the default OpenGL device:
      if ( !Video::setDevice( "OpenGL", width, height, bpp, fullScreen ) )
      {
           AssertFatal( false, "Could not find a compatible display device!" );
           return;
      }
   }
}


//--------------------------------------
ConsoleFunction( getDesktopResolution, const char*, 1, 1, "getDesktopResolution()" )
{
   argc; argv;
   char buffer[256];
   dSprintf( buffer, sizeof( buffer ), "%d %d %d", platState.desktopWidth, platState.desktopHeight, platState.desktopBitsPixel );
   char* returnString = Con::getReturnBuffer( dStrlen( buffer ) + 1 );
   dStrcpy( returnString, buffer );
   return( returnString ); 
}


//--------------------------------------
void Platform::init()
{
   // Set the platform variable for the scripts
   Con::setVariable( "$platform", "macos" );

   MacConsole::create();
   if ( !MacConsole::isEnabled() )
      Input::init();
   InitInput();   // as internal windowing input handles different stuff from Input object.

// not sure why this is here on mac, but so be it.
   DisplayDevice *dev = NULL;
   Con::printf( "Video Init:" );
   Video::init();
   dev = OpenGLDevice::create();
   // now safe to grab the right desktop size.
   GetDesktopState();
   // and now we can install the device.
   if ( Video::installDevice(dev) )
      Con::printf( "   Accelerated OpenGL display device detected." );
   else
      Con::printf( "   Accelerated OpenGL display device not detected." );
   Con::printf( "" );

//   sgDoubleByteEnabled = true; // !!!!! this right?
//   sgQueueEvents = true;
}

//--------------------------------------
void Platform::shutdown()
{
//   sgQueueEvents = false;

//   if(gMutexHandle)
//      CloseHandle(gMutexHandle);
   setWindowLocked( false );
   Video::destroy();
   Input::destroy();
   MacConsole::destroy();
}


//--------------------------------------
static U32 lastTimeTick;
static S32 passargc = 0;
static char **passargv = NULL;
static S32 appReturn = 0;

//--------------------------------------
static S32 run()
{
   createFontInit();
   windowSize.set(0,0);
   
   lastTimeTick = Platform::getRealMilliseconds();
   
   int ret = Game->main(passargc, (const char **)passargv);

   createFontShutdown();

   return ret;
}

//--------------------------------------
void Platform::initWindow(const Point2I &initialSize, const char *name)
{
/* // on the mac, video is currently initalized earlier...
   DisplayDevice *dev = NULL;
   Con::printf( "Video Init:" );
   Video::init();
   dev = OpenGLDevice::create();
   // now safe to grab the right desktop size.
   GetDesktopState();
   // and now we can install the device.
   if ( Video::installDevice(dev) )
      Con::printf( "   Accelerated OpenGL display device detected." );
   else
      Con::printf( "   Accelerated OpenGL display device not detected." );
   Con::printf( "" );
*/

   dSprintf(platState.appWindowTitle, sizeof(platState.appWindowTitle), name);
   InitWindow(initialSize); // this doesn't create the window -- gl subcode it.
   InitOpenGL();
  
   if (platState.appWindow)
   {
      gWindowCreated = true; // if we get in here, we really have a secondary window, not just a console...
#if TARG_MACCARB_EVENTS
      // install handlers to the given window.
      EventTargetRef winTarg = GetWindowEventTarget(platState.appWindow);
#define DEFAULT_HANDLERS      1
#if DEFAULT_HANDLERS
      InstallStandardEventHandler(winTarg);
      InstallStandardEventHandler(GetApplicationEventTarget());
#endif
   installCarbonEventHandlers();
#endif
   }
}


#if CARBEVENTS_RAEL
//--------------------------------------
pascal void DoRAELLoop(EventLoopTimerRef theTimer, void *userData)
{
   appReturn = run();
   QuitApplicationEventLoop();
}
#endif


//--------------------------------------
S32 main(S32 argc, const char **argv)
{
   bool optOutFromCmdline = false;
    
   // set up starting values.
   passargc = argc;
   passargv = (char**)argv;
  
   // Get rid of the -psn argument
   for(int j=0; j<passargc; j++)
      if(!strncmp(passargv[j], "-psn", 4))
	     passargv[j] = "";
		 
#if !TARGET_API_MAC_CARBON   
   InitGraf(&qd.thePort);      // init QuickDraw -- 'qd' is a Mac Global
   InitFonts();               // init the Font Manager
   InitWindows();               // init the Window Manager
   InitMenus();
   TEInit();
   InitDialogs( NULL );
#endif

   InitCursor();
   
   FlushEvents( everyEvent, 0 );
   SetEventMask(everyEvent);

   // save away OS version info into platState.
   if (Gestalt(gestaltSystemVersion, (SInt32 *) &(platState.osVersion)) == noErr)
   {
      platState.osX = false;
      if (platState.osVersion >= 0x01000)
         platState.osX = true;
   }

   // Update the current working directory.
   Platform::getWorkingDirectory();

   // this is yucky, but the easiest way to ignore the cmdline text file:
   #define KEYISDOWN(key) ((((unsigned char *)currKeyState)[key>>3] >> (key & 7)) & 1)
   KeyMap currKeyState;
   GetKeys(currKeyState);
   if (KEYISDOWN(0x38)) // check shift key -- actually LShift.
      optOutFromCmdline = true;

   // mac does not support command line arguments.  well, OSX does, but not easily for the average user...
   // it may be possible to get the comment field from the file
   // see DesktopManager and DTGetComment
   // BUT, for the moment, try to open a file "maccmdline.txt" and use first line.
   #define MAX_CMDLINE  2048
   static char cmdline[2048]; // make it 2K just in case...
   static const char *cmdargv[32]; // 32 max commands?
   if (!optOutFromCmdline)
   if (1) // used to check and only override if there were no args.  now, we merge them.
   {
      File cmdfile;
      S32 cmdargc=0;
      U32 cmdlen;
      File::Status cmderr;
      cmderr = cmdfile.open("maccmdline.txt", cmdfile.Read);
      if (cmderr == File::Ok)
      {
         cmderr = cmdfile.read(MAX_CMDLINE-1, cmdline, &cmdlen);
         if ((cmderr == File::Ok || cmderr == File::EOS) && cmdlen>1) // if empty file, don't bother...
         {
            cmdline[cmdlen] = 0; // null terminate.
            cmdlen++; // add the null to len.
            int i = 0;
            
            // first, reset the max length if there's a CR or LF.
            while (i<cmdlen)
            {
               if (cmdline[i]=='\n' || cmdline[i]=='\r')
               {
                  cmdline[i] = 0; // null terminate.
                  cmdlen = i+1; // set new length.
                  break;
               }
               i++;
            }
            
            // now build args.
            // arg[0] should be exe name/path.
            // on OSX, already there.  under 10.1, looks like there's a psn serial number as arg 2.  pain in the ass.
            // on OS9, we could put in the real thing, but I toss in a fake string for now.  !!!!TBD
            // !!!!TBD.  mac can't call getWorkingDir here, as it's not yet inited properly.

			    // Exclude the magic -psn process id parameter
				if(strncmp(argv[0], "-psn", 4))
			      cmdargv[cmdargc++] = argv[0];

            // arg[1] will be the first thing in the cmdline, if anything is there...
            cmdargv[cmdargc] = cmdline;

            i = 0;
            while (i<cmdlen)
            {
               if (cmdline[i]==0 || cmdline[i]==' ') // on nulls or spaces.
               {
                  cmdline[i] = 0;
                  cmdargc++; // we hit a command, so inc the count.
                  // set up for next command
                  cmdargv[cmdargc] = &(cmdline[i+1]); // start at char past null.
               }
               i++;
            }
            
            // now, tack on any other parameters from the real commandline.
            for (i=1; i<argc; i++)
            {
			    // Exclude the magic -psn process id parameter
				if(strncmp(argv[i], "-psn", 4))
					cmdargv[cmdargc++] = argv[i];
            }
            
//            if (cmdargc>1) // since app path always there... // for now, always used.
            { // copy/set the vars.
               passargc = cmdargc;
               passargv = (char**)cmdargv;
            }
         }
         cmdfile.close();
      }
   }

   appReturn = 0;
      
#if TARG_MACCARB_EVENTS
#if CARBEVENTS_RAEL
   carbEventsRAEL = true;
#endif

   if (carbEventsRAEL)
   {
      EventLoopTimerRef theTimer;
      // Install a one-shot timer to run the game, then call RAEL to install
      // the default application handler (which can't be called directly).
      InstallEventLoopTimer(GetCurrentEventLoop(), 0, 0, NewEventLoopTimerUPP(DoRAELLoop), NULL, &theTimer);
      RunApplicationEventLoop();
   }
   else
#endif
      appReturn = run(); // use the statics/globals rather than actually passing as params.
   
   InitCursor(); // don't leave it in a screwy state...

   return(appReturn);
}

//--------------------------------------
void TimeManager::process()
{
   U32 curTime = Platform::getRealMilliseconds(); // GTC returns Milliseconds, FYI.
   TimeEvent event;
   event.elapsedTime = curTime - lastTimeTick;
   if(event.elapsedTime > sgTimeManagerProcessInterval)
   {
      lastTimeTick = curTime;
      Game->postEvent(event);
   }
}


//--------------------------------------
F32 Platform::getRandom()
{
   return sgPlatRandom.randF();
}


//--------------------------------------
// Web browser function:
//--------------------------------------
#if !defined(TORQUE_OS_MAC_OSX)
#include <InternetConfig.h>
#endif
bool Platform::openWebBrowser( const char* webAddress )
{
   OSStatus err;
   ICInstance ic;
   long start, end, len;

#define kAppSignature      'GGTe'   
   err = ICStart(&ic, kAppSignature); // TBD!!!!!! replace with a const for the app signature.
   if (err==noErr)
   {
#if !TARGET_API_MAC_CARBON && !defined(TORQUE_OS_MAC_OSX)
      // this function is apparently outdated and not needed under Carbon.
      err = ICFindConfigFile(ic, 0, NULL);
      if (err==noErr)
#endif
      {
         len = dStrlen(webAddress);
         start = 0;
         end = len;
         err = ICLaunchURL(ic, (const unsigned char*)"\0", webAddress, len, &start, &end);
      }
      ICStop(ic);
   }
   
   return(err==noErr);
}

//--------------------------------------
void Platform::enableKeyboardTranslation(void)
{
   ActivateTSMDocument(platState.tsmDoc);
   platState.tsmActive=true;
   Con::printf("tsm doc should be active");
}

//--------------------------------------
void Platform::disableKeyboardTranslation(void)
{
   DeactivateTSMDocument(platState.tsmDoc);
   platState.tsmActive=false;
   Con::printf("tsm doc Deactivated");
}

//--------------------------------------
OSStatus DoTextInputCarbonEventHandling(EventHandlerCallRef nextHandler, EventRef theEvent, void* userData)
{
   UniChar  *text = NULL;
   UInt32   textLen;
   U32      charCount = 0;
   
   // be sure we have the right event type for this handler.
   U32 eventClass = GetEventClass(theEvent);
   U32 eventKind = GetEventKind(theEvent);
   
   if( eventClass != kEventClassTextInput )
      return eventNotHandledErr;

   switch(eventKind)
   {
      case kEventTextInputUnicodeForKeyEvent:
      {
         // get the input string from the text input event
         // first get the number of bytes required
         GetEventParameter( theEvent, kEventParamTextInputSendText, typeUnicodeText, NULL, 0, &textLen, NULL);
         charCount = textLen / sizeof(UniChar);
         text = new UniChar[charCount];

         // now that we've allocated space, get the buffer of text from the input method or keyboard.
         GetEventParameter( theEvent, kEventParamTextInputSendText, typeUnicodeText, NULL, textLen, NULL, text);

         break;
      }
      default:  // if we somehow get the wrong kind of event, let someone else handle it.
         return eventNotHandledErr;
   }
   
   
   // make torque events to enter that string.
   InputEvent torqueEvent;
   torqueEvent.deviceType  = KeyboardDeviceType;
   torqueEvent.deviceInst  = 0;
   torqueEvent.objType     = SI_TEXT;
   torqueEvent.objInst     = 0;
   torqueEvent.modifier    = 0;
   torqueEvent.action      = SI_MAKE;
   torqueEvent.fValue      = 1.0f;

   for( int i=0; i < charCount; i++)
   {
      torqueEvent.ascii = text[i];
      // evil temporary hack. I mean it. Temporary.
      // gets rid of the stray backquote in the console
      // switching to new event model may help, or bring up other prob.
      if(text[i] == '`' && charCount == 1)
         continue;
      Game->postEvent(torqueEvent);
   }

   return noErr;
}

//--------------------------------------
void installCarbonEventHandlers()
{
      EventTargetRef winTarg = GetWindowEventTarget(platState.appWindow);
      // set up the events we want to be notified of for our event handler.
      const int NUM_WIN_EVENT_TYPES = 3 + 5 + 3; // kb+mouse+wind
      static EventTypeSpec winEventTypes[NUM_WIN_EVENT_TYPES];
      static EventHandlerUPP winHandlerUPP = NULL;

      const int NUM_APP_EVENT_TYPES = 1 + 3 + 3 + 5; // AE+app+dupmouse/kb
      static EventTypeSpec appEventTypes[NUM_APP_EVENT_TYPES];
      static EventHandlerUPP appHandlerUPP = NULL;
      
      const int NUM_TEXT_EVENT_TYPES = 1;
      static EventTypeSpec textEventTypes[NUM_TEXT_EVENT_TYPES];
      static EventHandlerUPP textHandlerUPP = NULL;

      int c = 0;

      if(textHandlerUPP==NULL)
      {
         c = 0;
         textEventTypes[c].eventClass = kEventClassTextInput;
         textEventTypes[c++].eventKind = kEventTextInputUnicodeForKeyEvent;
         
         textHandlerUPP = NewEventHandlerUPP(DoTextInputCarbonEventHandling);
      }


      if (winHandlerUPP==NULL)
      {
         c = 0;
         winEventTypes[c].eventClass = kEventClassKeyboard;
         winEventTypes[c++].eventKind = kEventRawKeyDown;
         winEventTypes[c].eventClass = kEventClassKeyboard;
         winEventTypes[c++].eventKind = kEventRawKeyUp;
         winEventTypes[c].eventClass = kEventClassKeyboard;
         winEventTypes[c++].eventKind = kEventRawKeyRepeat;
   // don't do this until we decide we really need it to get raw modifier keys...
   //      eventTypes[c].eventClass = kEventClassKeyboard;
   //      eventTypes[c++].eventKind = kEventRawKeyModifiersChanged;

         winEventTypes[c].eventClass = kEventClassMouse;
         winEventTypes[c++].eventKind = kEventMouseDown;
         winEventTypes[c].eventClass = kEventClassMouse;
         winEventTypes[c++].eventKind = kEventMouseUp;
         winEventTypes[c].eventClass = kEventClassMouse;
         winEventTypes[c++].eventKind = kEventMouseMoved;
         winEventTypes[c].eventClass = kEventClassMouse;
         winEventTypes[c++].eventKind = kEventMouseDragged;
         winEventTypes[c].eventClass = kEventClassMouse;
         winEventTypes[c++].eventKind = kEventMouseWheelMoved;

   // don't need this unless we want special handling.
         winEventTypes[c].eventClass = kEventClassWindow;
         winEventTypes[c++].eventKind = kEventWindowDrawContent;
         winEventTypes[c].eventClass = kEventClassWindow;
         winEventTypes[c++].eventKind = kEventWindowActivated;
         winEventTypes[c].eventClass = kEventClassWindow;
         winEventTypes[c++].eventKind = kEventWindowDeactivated;

         winHandlerUPP = NewEventHandlerUPP(DoWinCarbonEventHandling);
      }
      
      if (appHandlerUPP==NULL)
      {
         c = 0;
         appEventTypes[c].eventClass = kEventClassAppleEvent;
         appEventTypes[c++].eventKind = kEventAppleEvent; // it's always an appleevent

         appEventTypes[c].eventClass = kEventClassApplication;
         appEventTypes[c++].eventKind = kEventAppQuit;
         appEventTypes[c].eventClass = kEventClassApplication;
         appEventTypes[c++].eventKind = kEventAppActivated;
         appEventTypes[c].eventClass = kEventClassApplication;
         appEventTypes[c++].eventKind = kEventAppDeactivated;
         
         // since if in windowed mode, these can all occur outside window bounds, we need to
         // force-propagate the msg.
         appEventTypes[c].eventClass = kEventClassKeyboard;
         appEventTypes[c++].eventKind = kEventRawKeyDown;
         appEventTypes[c].eventClass = kEventClassKeyboard;
         appEventTypes[c++].eventKind = kEventRawKeyUp;
         appEventTypes[c].eventClass = kEventClassKeyboard;
         appEventTypes[c++].eventKind = kEventRawKeyRepeat;
   // don't do this until we decide we really need it to get raw modifier keys...
   //      eventTypes[c].eventClass = kEventClassKeyboard;
   //      eventTypes[c++].eventKind = kEventRawKeyModifiersChanged;

         appEventTypes[c].eventClass = kEventClassMouse;
         appEventTypes[c++].eventKind = kEventMouseDown;
         appEventTypes[c].eventClass = kEventClassMouse;
         appEventTypes[c++].eventKind = kEventMouseUp;
         appEventTypes[c].eventClass = kEventClassMouse;
         appEventTypes[c++].eventKind = kEventMouseMoved;
         appEventTypes[c].eventClass = kEventClassMouse;
         appEventTypes[c++].eventKind = kEventMouseDragged;
         appEventTypes[c].eventClass = kEventClassMouse;
         appEventTypes[c++].eventKind = kEventMouseWheelMoved;

         appHandlerUPP = NewEventHandlerUPP(DoAppCarbonEventHandling);
      }
      
      // this installs into the window -- window doesn't always get all events, such as App events
      InstallEventHandler (winTarg, winHandlerUPP, NUM_WIN_EVENT_TYPES, winEventTypes, NULL, &gWinEventHandlerRef);
      // this installs at the app level.
      InstallEventHandler (GetApplicationEventTarget(), appHandlerUPP, NUM_APP_EVENT_TYPES, appEventTypes, NULL, &gAppEventHandlerRef);
      // this installs a handler for unicode text input
      InstallEventHandler (GetApplicationEventTarget(), textHandlerUPP, NUM_TEXT_EVENT_TYPES, textEventTypes, NULL, &gTextEventHandlerRef);
      
      carbonEventsReady = true;
}

void removeCarbonEventHandlers()
{
   RemoveEventHandler(gWinEventHandlerRef);
   RemoveEventHandler(gAppEventHandlerRef);
}

ConsoleFunction(testFloatingWindowLevel,void,1,1,"")
{
   Con::printf(" Sheilding window level is %x",CGShieldingWindowLevel());
   SetWindowGroupLevel( GetWindowGroupOfClass(kUtilityWindowClass), 1031);
   SetWindowGroupLevel( GetWindowGroupOfClass(kFloatingWindowClass), 1030);   
   SetWindowGroupLevel( GetWindowGroupOfClass(kAlertWindowClass), 1031);
}
