/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * The contents of this file are subject to the Netscape Public License
 * Version 1.0 (the "NPL"); you may not use this file except in
 * compliance with the NPL.  You may obtain a copy of the NPL at
 * http://www.mozilla.org/NPL/
 *
 * Software distributed under the NPL is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
 * for the specific language governing rights and limitations under the
 * NPL.
 *
 * The Initial Developer of this code under the NPL is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
 * Reserved.
 */

#include "nsMacEventHandler.h"

#include "nsWindow.h"
#include "nsMacWindow.h"
#include "nsToolkit.h"
#include "prinrval.h"

#include <ToolUtils.h>
#include <DiskInit.h>
#include <LowMem.h>
#include <TextServices.h>
#include <UnicodeConverter.h>
#include <Script.h>

// from MacHeaders.c
#ifndef topLeft
	#define topLeft(r)	(((Point *) &(r))[0])
#endif
#ifndef botRight
	#define botRight(r)	(((Point *) &(r))[1])
#endif

PRBool	nsMacEventHandler::mInBackground = PR_FALSE;

//-------------------------------------------------------------------------
//
// nsMacEventHandler constructor/destructor
//
//-------------------------------------------------------------------------
nsMacEventHandler::nsMacEventHandler(nsMacWindow* aTopLevelWidget)
{
	OSErr	err;
	InterfaceTypeList supportedServices;
	
	mTopLevelWidget			= aTopLevelWidget;
	mLastWidgetHit			= nsnull;
	mLastWidgetPointed	= nsnull;
	mTSMDocument				= nsnull;
	
	//
	// create a TSMDocument for this window.  We are allocating a TSM document for
	// each Mac window
	//
	supportedServices[0] = kTextService;
	err = ::NewTSMDocument(1,supportedServices,&mTSMDocument,(long)this);
	NS_ASSERTION(err==noErr,"nsMacEventHandler::nsMacEventHandler: NewTSMDocument failed.");

	printf("nsMacEventHandler::nsMacEventHandler: created TSMDocument[%p]\n",mTSMDocument);
		
	mIMEIsComposing = PR_FALSE;
	mIMECompositionString = nsnull;
	mIMECompositionStringSize = 0;
	mIMECompositionStringLength = 0;

}


nsMacEventHandler::~nsMacEventHandler()
{
	if (mLastWidgetPointed)
		mLastWidgetPointed->RemoveDeleteObserver(this);

	if (mLastWidgetHit)
		mLastWidgetHit->RemoveDeleteObserver(this);
		
	if (mTSMDocument)
		(void)::DeleteTSMDocument(mTSMDocument);
}


void nsMacEventHandler::NotifyDelete(void* aDeletedObject)
{
	if (mLastWidgetPointed == aDeletedObject)
		mLastWidgetPointed = nsnull;

	if (mLastWidgetHit == aDeletedObject)
		mLastWidgetHit = nsnull;
}


#pragma mark -
//-------------------------------------------------------------------------
//
// HandleOSEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleOSEvent ( EventRecord& aOSEvent )
{
	PRBool retVal = PR_FALSE;

	switch (aOSEvent.what)
	{
		case keyUp:
		case keyDown:
		case autoKey:
			retVal = HandleKeyEvent(aOSEvent);
			break;

		case activateEvt:
			retVal = HandleActivateEvent(aOSEvent);
			break;

		case updateEvt:
			retVal = HandleUpdateEvent(aOSEvent);
			break;

		case mouseDown:
			retVal = HandleMouseDownEvent(aOSEvent);
			break;

		case mouseUp:
			retVal = HandleMouseUpEvent(aOSEvent);
			break;

		case osEvt:
			unsigned char eventType = ((aOSEvent.message >> 24) & 0x00ff);
			if (eventType == suspendResumeMessage)
			{
				if ((aOSEvent.message & 1) == resumeFlag)
					mInBackground = PR_FALSE;		// resume message
				else
					mInBackground = PR_TRUE;		// suspend message
			}
			else {
				if (! mInBackground)
					retVal = HandleMouseMoveEvent(aOSEvent);
			}
			break;
	
		case nullEvent:
			if (! mInBackground)
				retVal = HandleMouseMoveEvent(aOSEvent);
			break;
	}

	return retVal;
}


//-------------------------------------------------------------------------
//
// Handle Menu commands
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleMenuCommand(
  EventRecord& aOSEvent,
  long         aMenuResult)
{
	// get the focused widget
	nsWindow* focusedWidget = mTopLevelWidget;
	nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
	if (toolkit)
		focusedWidget = toolkit->GetFocus();
	
	if (!focusedWidget)
	{
	  NS_WARNING("Throwing away menu event because there is no focused widget");
		return PR_FALSE;
	}
	
	// nsEvent
	nsMenuEvent menuEvent;
	menuEvent.eventStructType = NS_MENU_EVENT;
	menuEvent.message		= NS_MENU_SELECTED;
	menuEvent.point.x		= aOSEvent.where.h;
	menuEvent.point.y		= aOSEvent.where.v;
	menuEvent.time			= PR_IntervalNow();

	// nsGUIEvent
	menuEvent.widget		= focusedWidget;
	menuEvent.nativeMsg	= (void*)&aOSEvent;

	// nsMenuEvent
	menuEvent.mMenuItem	= nsnull;						//¥TODO: initialize mMenuItem
	menuEvent.mCommand	= aMenuResult;

	// dispatch the menu event: if it is not processed by the focused widget,
	// propagate the event through the different parents all the way up to the window
	PRBool eventHandled = focusedWidget->DispatchWindowEvent(menuEvent);
	
	if (! eventHandled)
	{
		nsCOMPtr<nsWindow> grandParent;
		nsCOMPtr<nsWindow> parent ( dont_AddRef((nsWindow*)focusedWidget->GetParent()) );
		while (parent)
		{
			menuEvent.widget = parent;
			eventHandled = parent->DispatchWindowEvent(menuEvent);
			if (eventHandled)
			{
				break;
			}
			else
			{
				grandParent = dont_AddRef((nsWindow*)parent->GetParent());
				parent = grandParent;
			}
		}
	}

	return eventHandled;
}


//-------------------------------------------------------------------------
//
// DragEvent
//
//-------------------------------------------------------------------------
//
// Someone on the outside told us that something related to a drag is happening. The
// exact event type is passed in as |aMessage|. We need to send this event into Gecko 
// for processing. Create a Gecko event (using the appropriate message type) and pass
// it along.
//
// ¥¥¥THIS REALLY NEEDS TO BE CLEANED UP! TOO MUCH CODE COPIED FROM ConvertOSEventToMouseEvent
//
PRBool nsMacEventHandler::DragEvent ( unsigned int aMessage, Point aMouseGlobal, UInt16 aKeyModifiers )
{
	nsMouseEvent geckoEvent;

	// convert the mouse to local coordinates. We have to do all the funny port origin
	// stuff just in case it has been changed.
	Point hitPointLocal = aMouseGlobal;
#if TARGET_CARBON
	GrafPtr grafPort = reinterpret_cast<GrafPtr>(mTopLevelWidget->GetNativeData(NS_NATIVE_GRAPHIC));
	::SetPort(grafPort);
	Rect savePortRect;
	::GetPortBounds(grafPort, &savePortRect);
#else
	GrafPtr grafPort = static_cast<GrafPort*>(mTopLevelWidget->GetNativeData(NS_NATIVE_GRAPHIC));
	::SetPort(grafPort);
	Rect savePortRect = grafPort->portRect;
#endif
	::SetOrigin(0, 0);
	::GlobalToLocal(&hitPointLocal);
	::SetOrigin(savePortRect.left, savePortRect.top);
	nsPoint widgetHitPoint(hitPointLocal.h, hitPointLocal.v);

	nsWindow* widgetHit = mTopLevelWidget->FindWidgetHit(hitPointLocal);
	if ( widgetHit ) {
		// adjust from local coordinates to window coordinates in case the top level widget
		// isn't at 0, 0
		nsRect bounds;
		mTopLevelWidget->GetBounds(bounds);
		nsPoint widgetOrigin(bounds.x, bounds.y);
		widgetHit->LocalToWindowCoordinate(widgetOrigin);
		widgetHitPoint.MoveBy(-widgetOrigin.x, -widgetOrigin.y);
	}
	else
	  widgetHit = mTopLevelWidget;
		
	// nsEvent
	geckoEvent.eventStructType = NS_DRAGDROP_EVENT;
	geckoEvent.message = aMessage;
	geckoEvent.point = widgetHitPoint;
	geckoEvent.time	= PR_IntervalNow();

	// nsGUIEvent
	geckoEvent.widget = widgetHit;
	geckoEvent.nativeMsg = nsnull;

	// nsInputEvent
	geckoEvent.isShift = ((aKeyModifiers & shiftKey) != 0);
	geckoEvent.isControl = ((aKeyModifiers & controlKey) != 0);
	geckoEvent.isAlt = ((aKeyModifiers & optionKey) != 0);
	geckoEvent.isCommand = ((aKeyModifiers & cmdKey) != 0);

	// nsMouseEvent
	geckoEvent.clickCount = 1;
	
	widgetHit->DispatchMouseEvent(geckoEvent);
	
	return PR_TRUE;
	
} // DropOccurred


#pragma mark -

//-------------------------------------------------------------------------
//
// ConvertMacToRaptorKeyCode
//
//-------------------------------------------------------------------------


// Key code constants
enum
{
	kEscapeKeyCode			= 0x35,
	kShiftKeyCode				= 0x38,
	kCapsLockKeyCode		= 0x39,
	kControlKeyCode			= 0x3B,
	kOptionkeyCode			= 0x3A,		// left and right option keys
	kClearKeyCode				= 0x47,
	
	// function keys
	kF1KeyCode					= 0x7A,
	kF2KeyCode					= 0x78,
	kF3KeyCode					= 0x63,
	kF4KeyCode					= 0x76,
	kF5KeyCode					= 0x60,
	kF6KeyCode					= 0x61,
	kF7KeyCode					= 0x62,
	kF8KeyCode					= 0x64,
	kF9KeyCode					= 0x65,
	kF10KeyCode					= 0x6D,
	kF11KeyCode					= 0x67,
	kF12KeyCode					= 0x6F,
	kF13KeyCode					= 0x69,
	kF14KeyCode					= 0x6B,
	kF15KeyCode					= 0x71,
	
	kPrintScreenKeyCode	= kF13KeyCode,
	kScrollLockKeyCode	= kF14KeyCode,
	kPauseKeyCode				= kF15KeyCode,
	
	// keypad
	kKeypad0KeyCode			= 0x52,
	kKeypad1KeyCode			= 0x53,
	kKeypad2KeyCode			= 0x54,
	kKeypad3KeyCode			= 0x55,
	kKeypad4KeyCode			= 0x56,
	kKeypad5KeyCode			= 0x57,
	kKeypad6KeyCode			= 0x58,
	kKeypad7KeyCode			= 0x59,
	kKeypad8KeyCode			= 0x5B,
	kKeypad9KeyCode			= 0x5C,
	
	kKeypadMultiplyKeyCode	= 0x43,
	kKeypadAddKeyCode				= 0x45,
	kKeypadSubtractKeyCode	= 0x4E,
	kKeypadDecimalKeyCode		= 0x41,
	kKeypadDivideKeyCode		= 0x4B,
	kKeypadEqualsKeyCode		= 0x51,			// no correpsonding raptor key code
	
	kInsertKeyCode					= 0x72,				// also help key
	kDeleteKeyCode					= 0x75,				// also forward delete key
	kTabKeyCode							= 0x30,
	kHomeKeyCode						= 0x73,	
	kEndKeyCode							= 0x77,
	kPageUpKeyCode					= 0x74,
	kPageDownKeyCode				= 0x79,
	kLeftArrowKeyCode				= 0x7B,
	kRightArrowKeyCode			= 0x7C,
	kUpArrowKeyCode					= 0x7E,
	kDownArrowKeyCode				= 0x7D
	
};

static PRUint32 ConvertMacToRaptorKeyCode(UInt32 eventMessage, UInt32 eventModifiers)
{
	UInt8			charCode = (eventMessage & charCodeMask);
	UInt8			keyCode = (eventMessage & keyCodeMask) >> 8;
	PRUint32	raptorKeyCode = 0;
	
	switch (keyCode)
	{
//	case ??							:				raptorKeyCode = NS_VK_CANCEL;		break;			// don't know what this key means. Nor does joki

// modifiers. We don't get separate events for these
		case kEscapeKeyCode:				raptorKeyCode = NS_VK_ESCAPE;					break;
		case kShiftKeyCode:					raptorKeyCode = NS_VK_SHIFT;					break;
		case kCapsLockKeyCode:			raptorKeyCode = NS_VK_CAPS_LOCK;			break;
		case kControlKeyCode:				raptorKeyCode = NS_VK_CONTROL;				break;
		case kOptionkeyCode:				raptorKeyCode = NS_VK_ALT;						break;
		case kClearKeyCode:					raptorKeyCode = NS_VK_CLEAR;					break;

// function keys
		case kF1KeyCode:						raptorKeyCode = NS_VK_F1;							break;
		case kF2KeyCode:						raptorKeyCode = NS_VK_F2;							break;
		case kF3KeyCode:						raptorKeyCode = NS_VK_F3;							break;
		case kF4KeyCode:						raptorKeyCode = NS_VK_F4;							break;
		case kF5KeyCode:						raptorKeyCode = NS_VK_F5;							break;
		case kF6KeyCode:						raptorKeyCode = NS_VK_F6;							break;
		case kF7KeyCode:						raptorKeyCode = NS_VK_F7;							break;
		case kF8KeyCode:						raptorKeyCode = NS_VK_F8;							break;
		case kF9KeyCode:						raptorKeyCode = NS_VK_F9;							break;
		case kF10KeyCode:						raptorKeyCode = NS_VK_F10;						break;
		case kF11KeyCode:						raptorKeyCode = NS_VK_F11;						break;
		case kF12KeyCode:						raptorKeyCode = NS_VK_F12;						break;
//	case kF13KeyCode:						raptorKeyCode = NS_VK_F13;						break;		// clash with the 3 below
//	case kF14KeyCode:						raptorKeyCode = NS_VK_F14;						break;
//	case kF15KeyCode:						raptorKeyCode = NS_VK_F15;						break;
		case kPauseKeyCode:					raptorKeyCode = NS_VK_PAUSE;					break;
		case kScrollLockKeyCode:		raptorKeyCode = NS_VK_SCROLL_LOCK;		break;
		case kPrintScreenKeyCode:		raptorKeyCode = NS_VK_PRINTSCREEN;		break;
	
// keypad
		case kKeypad0KeyCode:				raptorKeyCode = NS_VK_NUMPAD0;				break;
		case kKeypad1KeyCode:				raptorKeyCode = NS_VK_NUMPAD1;				break;
		case kKeypad2KeyCode:				raptorKeyCode = NS_VK_NUMPAD2;				break;
		case kKeypad3KeyCode:				raptorKeyCode = NS_VK_NUMPAD3;				break;
		case kKeypad4KeyCode:				raptorKeyCode = NS_VK_NUMPAD4;				break;
		case kKeypad5KeyCode:				raptorKeyCode = NS_VK_NUMPAD5;				break;
		case kKeypad6KeyCode:				raptorKeyCode = NS_VK_NUMPAD6;				break;
		case kKeypad7KeyCode:				raptorKeyCode = NS_VK_NUMPAD7;				break;
		case kKeypad8KeyCode:				raptorKeyCode = NS_VK_NUMPAD8;				break;
		case kKeypad9KeyCode:				raptorKeyCode = NS_VK_NUMPAD9;				break;

		case kKeypadMultiplyKeyCode:	raptorKeyCode = NS_VK_MULTIPLY;			break;
		case kKeypadAddKeyCode:				raptorKeyCode = NS_VK_ADD;					break;
		case kKeypadSubtractKeyCode:	raptorKeyCode = NS_VK_SUBTRACT;			break;
		case kKeypadDecimalKeyCode:		raptorKeyCode = NS_VK_DECIMAL;			break;
		case kKeypadDivideKeyCode:		raptorKeyCode = NS_VK_DIVIDE;				break;
//	case ??								:				raptorKeyCode = NS_VK_SEPARATOR;		break;


// these may clash with forward delete and help
//	case kInsertKeyCode:				raptorKeyCode = NS_VK_INSERT;					break;
//	case kDeleteKeyCode:				raptorKeyCode = NS_VK_DELETE;					break;

		default:
		
				// if we haven't gotten the key code already, look at the char code
				switch (charCode)
				{
					case kReturnCharCode:				raptorKeyCode = NS_VK_RETURN;				break;
					case kEnterCharCode:				raptorKeyCode = NS_VK_RETURN;				break;			// fix me!
					case kBackspaceCharCode:		raptorKeyCode = NS_VK_BACK;					break;
					case kDeleteCharCode:				raptorKeyCode = NS_VK_DELETE;				break;
					case kTabCharCode:					raptorKeyCode = NS_VK_TAB;					break;

					case kHomeCharCode:					raptorKeyCode = NS_VK_HOME;					break;
					case kEndCharCode:					raptorKeyCode = NS_VK_END;					break;
					case kPageUpCharCode:				raptorKeyCode = NS_VK_PAGE_UP;			break;
					case kPageDownCharCode:			raptorKeyCode = NS_VK_PAGE_DOWN;		break;

					case kLeftArrowCharCode:		raptorKeyCode = NS_VK_LEFT;					break;
					case kRightArrowCharCode:		raptorKeyCode = NS_VK_RIGHT;				break;
					case kUpArrowCharCode:			raptorKeyCode = NS_VK_UP;						break;
					case kDownArrowCharCode:		raptorKeyCode = NS_VK_DOWN;					break;
					case ' ':										raptorKeyCode = NS_VK_SPACE;				break;
					case ';':										raptorKeyCode = NS_VK_SEMICOLON;		break;
					case '=':										raptorKeyCode = NS_VK_EQUALS;				break;
					case ',':										raptorKeyCode = NS_VK_COMMA;				break;
					case '.':										raptorKeyCode = NS_VK_PERIOD;				break;
					case '/':										raptorKeyCode = NS_VK_SLASH;				break;
					case '`':										raptorKeyCode = NS_VK_BACK_QUOTE;		break;
					case '{':
					case '[':										raptorKeyCode = NS_VK_OPEN_BRACKET;	break;
					case '\\':									raptorKeyCode = NS_VK_BACK_SLASH;		break;
					case '}':
					case ']':										raptorKeyCode = NS_VK_CLOSE_BRACKET;	break;
					case '\'':
					case '"':										raptorKeyCode = NS_VK_QUOTE;				break;
					
					default:
						
						if (charCode >= '0' && charCode <= '9')		// numerals
						{
							raptorKeyCode = charCode;
						}
						else if (charCode >= 'a' && charCode <= 'z')		// lowercase
						{
							raptorKeyCode = toupper(charCode);
						}
						else if (charCode >= 'A' && charCode <= 'Z')		// uppercase
						{
							raptorKeyCode = charCode;
						}

						break;
				}
	}

	return raptorKeyCode;
}


//-------------------------------------------------------------------------
//
// InitializeKeyEvent
//
//-------------------------------------------------------------------------

void nsMacEventHandler::InitializeKeyEvent(nsKeyEvent& aKeyEvent, EventRecord& aOSEvent, nsWindow* focusedWidget, PRUint32 message)
{
	//
	// initalize the basic message parts
	//
	aKeyEvent.eventStructType = NS_KEY_EVENT;
	aKeyEvent.message 		= message;
	aKeyEvent.point.x			= 0;
	aKeyEvent.point.y			= 0;
	aKeyEvent.time				= PR_IntervalNow();
	
	//
	// initalize the GUI event parts
	//
	aKeyEvent.widget			= focusedWidget;
	aKeyEvent.nativeMsg		= (void*)&aOSEvent;
	
	//
	// nsInputEvent parts
	//
	aKeyEvent.isShift			= ((aOSEvent.modifiers & shiftKey) != 0);
	aKeyEvent.isControl		= ((aOSEvent.modifiers & controlKey) != 0);
	aKeyEvent.isAlt				= ((aOSEvent.modifiers & optionKey) != 0);
	aKeyEvent.isCommand		= ((aOSEvent.modifiers & cmdKey) != 0);
	
	//
	// nsKeyEvent parts
	//
	aKeyEvent.keyCode		= ConvertMacToRaptorKeyCode(aOSEvent.message, aOSEvent.modifiers);
	aKeyEvent.charCode	= aOSEvent.message & charCodeMask;		// will be translated to Unicode, see ConvertKeyEventToUnicode
}


//-------------------------------------------------------------------------
//
// IsSpecialRaptorKey
//
//-------------------------------------------------------------------------

PRBool nsMacEventHandler::IsSpecialRaptorKey(UInt32 macKeyCode)
{
	PRBool	isSpecial;

	// 
	// this table is used to make the macintosh virtual key generation behave the same
	// as windows and linux
	//	
	switch (macKeyCode)
	{
// modifiers. We don't get separate events for these
		case kEscapeKeyCode:				isSpecial = PR_TRUE; break;
		case kShiftKeyCode:					isSpecial = PR_TRUE; break;
		case kCapsLockKeyCode:			isSpecial = PR_TRUE; break;
		case kControlKeyCode:				isSpecial = PR_TRUE; break;
		case kOptionkeyCode:				isSpecial = PR_TRUE; break;
		case kClearKeyCode:					isSpecial = PR_TRUE; break;

// function keys
		case kF1KeyCode:					isSpecial = PR_TRUE; break;
		case kF2KeyCode:					isSpecial = PR_TRUE; break;
		case kF3KeyCode:					isSpecial = PR_TRUE; break;
		case kF4KeyCode:					isSpecial = PR_TRUE; break;
		case kF5KeyCode:					isSpecial = PR_TRUE; break;
		case kF6KeyCode:					isSpecial = PR_TRUE; break;
		case kF7KeyCode:					isSpecial = PR_TRUE; break;
		case kF8KeyCode:					isSpecial = PR_TRUE; break;
		case kF9KeyCode:					isSpecial = PR_TRUE; break;
		case kF10KeyCode:					isSpecial = PR_TRUE; break;
		case kF11KeyCode:					isSpecial = PR_TRUE; break;
		case kF12KeyCode:					isSpecial = PR_TRUE; break;
		case kPauseKeyCode:				isSpecial = PR_TRUE; break;
		case kScrollLockKeyCode:	isSpecial = PR_TRUE; break;
		case kPrintScreenKeyCode:	isSpecial = PR_TRUE; break;
	
// keypad
		case kKeypad0KeyCode:				isSpecial = PR_TRUE; break;
		case kKeypad1KeyCode:				isSpecial = PR_TRUE; break;
		case kKeypad2KeyCode:				isSpecial = PR_TRUE; break;
		case kKeypad3KeyCode:				isSpecial = PR_TRUE; break;
		case kKeypad4KeyCode:				isSpecial = PR_TRUE; break;
		case kKeypad5KeyCode:				isSpecial = PR_TRUE; break;
		case kKeypad6KeyCode:				isSpecial = PR_TRUE; break;
		case kKeypad7KeyCode:				isSpecial = PR_TRUE; break;
		case kKeypad8KeyCode:				isSpecial = PR_TRUE; break;
		case kKeypad9KeyCode:				isSpecial = PR_TRUE; break;

		case kKeypadMultiplyKeyCode:		isSpecial = PR_TRUE; break;
		case kKeypadAddKeyCode:					isSpecial = PR_TRUE; break;
		case kKeypadSubtractKeyCode:		isSpecial = PR_TRUE; break;
		case kKeypadDecimalKeyCode:			isSpecial = PR_TRUE; break;
		case kKeypadDivideKeyCode:			isSpecial = PR_TRUE; break;	


		case kDeleteKeyCode:				isSpecial = PR_TRUE; break;
		case kTabKeyCode:						isSpecial = PR_TRUE; break;

		case kHomeKeyCode:					isSpecial = PR_TRUE; break;	
		case kEndKeyCode:						isSpecial = PR_TRUE; break;
		case kPageUpKeyCode:				isSpecial = PR_TRUE; break;
		case kPageDownKeyCode:			isSpecial = PR_TRUE; break;
		case kLeftArrowKeyCode:			isSpecial = PR_TRUE; break;
		case kRightArrowKeyCode:		isSpecial = PR_TRUE; break;
		case kUpArrowKeyCode:				isSpecial = PR_TRUE; break;
		case kDownArrowKeyCode:			isSpecial = PR_TRUE; break;
		
		default:							isSpecial = PR_FALSE; break;
	}
	return isSpecial;
}


//-------------------------------------------------------------------------
//
// ConvertKeyEventToUnicode
//
//-------------------------------------------------------------------------

void nsMacEventHandler::ConvertKeyEventToUnicode(nsKeyEvent& aKeyEvent, EventRecord& aOSEvent)
{
	aKeyEvent.charCode = 0;

	char charResult = aOSEvent.message & charCodeMask;
	
	//
	// get the script of text for Unicode conversion
	//
	ScriptCode textScript = (ScriptCode)GetScriptManagerVariable(smKeyScript);

	//
	// convert our script code (smKeyScript) to a TextEncoding 
	//
	TextEncoding textEncodingFromScript;
	OSErr err = ::UpgradeScriptInfoToTextEncoding(textScript, kTextLanguageDontCare, kTextRegionDontCare, nsnull,
											&textEncodingFromScript);
	NS_ASSERTION(err == noErr, "nsMacEventHandler::ConvertKeyEventToUnicode: UpgradeScriptInfoToTextEncoding failed.");
	if (err != noErr) return;
	
	TextToUnicodeInfo	textToUnicodeInfo;
	err = ::CreateTextToUnicodeInfoByEncoding(textEncodingFromScript,&textToUnicodeInfo);
	NS_ASSERTION(err == noErr, "nsMacEventHandler::ConvertKeyEventToUnicode: CreateUnicodeToTextInfoByEncoding failed.");
	if (err != noErr) return;

	//
	// convert to Unicode
	//
	ByteCount result_size, source_read;
	PRUnichar unicharResult;
	err = ::ConvertFromTextToUnicode(textToUnicodeInfo,
									sizeof(char),&charResult,
									kUnicodeLooseMappingsMask,
									0,NULL,NULL,NULL,
									sizeof(PRUnichar),&source_read,
									&result_size,&unicharResult);
	::DisposeTextToUnicodeInfo(&textToUnicodeInfo);
	NS_ASSERTION(err == noErr, "nsMacEventHandler::ConvertKeyEventToUnicode: ConverFromTextToUnicode failed.");
	if (err != noErr) return;

	aKeyEvent.charCode = unicharResult;
}


//-------------------------------------------------------------------------
//
// HandleKeyEvent
//
//-------------------------------------------------------------------------

PRBool nsMacEventHandler::HandleKeyEvent(EventRecord& aOSEvent)
{
	nsresult result;

	// get the focused widget
	nsWindow* focusedWidget = mTopLevelWidget;	
	nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
	if (toolkit)
		focusedWidget = toolkit->GetFocus();
	
	if (!focusedWidget)
	{
  	NS_WARNING("Throwing away key event because there is no focused widget");
		return PR_FALSE;
	}
	
	// nsEvent
	nsKeyEvent	keyEvent;
	switch (aOSEvent.what)
	{
		case keyUp:
			InitializeKeyEvent(keyEvent,aOSEvent,focusedWidget,NS_KEY_UP);
			result = focusedWidget->DispatchWindowEvent(keyEvent);
			break;

		case keyDown:	
		case autoKey:
			InitializeKeyEvent(keyEvent,aOSEvent,focusedWidget,NS_KEY_DOWN);
			result = focusedWidget->DispatchWindowEvent(keyEvent);
			if (! IsSpecialRaptorKey((aOSEvent.message & keyCodeMask) >> 8))
			{
				InitializeKeyEvent(keyEvent,aOSEvent,focusedWidget,NS_KEY_PRESS);
				ConvertKeyEventToUnicode(keyEvent,aOSEvent);
				result = focusedWidget->DispatchWindowEvent(keyEvent);
			}
			break;
	}

	return result;
}

#pragma mark -
//-------------------------------------------------------------------------
//
// HandleActivateEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleActivateEvent(EventRecord& aOSEvent)
{
	OSErr	err;
	nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
	if (toolkit)
	{
		Boolean isActive = ((aOSEvent.modifiers & activeFlag) != 0);
		if (isActive)
		{
			//
			// Activate The TSMDocument associated with this handler
			//
			if (mTSMDocument)
				err = ::ActivateTSMDocument(mTSMDocument);
#if 0
			NS_ASSERTION(err==noErr,"nsMacEventHandler::HandleActivateEvent: ActivateTSMDocument failed");
			printf("nsEventHandler::HandleActivateEvent: ActivateTSMDocument[%p]\n",mTSMDocument);
#endif
			
			//¥TODO: retrieve the focused widget for that window
			
			nsWindow*	focusedWidget = mTopLevelWidget;
			toolkit->SetFocus(focusedWidget);
			nsIMenuBar* menuBar = focusedWidget->GetMenuBar();
			if (menuBar)
			{
			  MenuHandle menuHandle = nsnull;

			  menuBar->GetNativeData((void *)menuHandle);
			  ::SetMenuBar((Handle)menuHandle);
			  menuBar->Paint();
			}
			else
			{
			  //¥TODO:	if the focusedWidget doesn't have a menubar,
			  //				look all the way up to the window
			  //				until one of the parents has a menubar
			}

			//¥TODO: set the menu bar here
		}
		else
		{
			//
			// Deactivate the TSMDocument assoicated with this EventHandler
			//
			if (mTSMDocument)
				err = ::DeactivateTSMDocument(mTSMDocument);
#if 0
			NS_ASSERTION(err==noErr,"nsMacEventHandler::HandleActivateEvent: DeactivateTSMDocument failed");
			printf("nsEventHandler::HandleActivateEvent: DeactivateTSMDocument[%p]\n",mTSMDocument);
#endif
			
			//¥TODO: save the focused widget for that window
			toolkit->SetFocus(nsnull);
	
			//nsIMenuBar* menuBarInterface = mTopLevelWidget->GetMenuBar();
			//if (menuBarInterface)
			//{
				//Handle menuBar = ::GetMenuBar(); // Get a copy of the menu list
				//menuBarInterface->SetNativeData((void*)menuBar);
			//}
		}
	}
	return PR_TRUE;
}


//-------------------------------------------------------------------------
//
// HandleUpdateEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleUpdateEvent(EventRecord& aOSEvent)
{
	mTopLevelWidget->HandleUpdateEvent();

	return PR_TRUE;
}


//-------------------------------------------------------------------------
//
// HandleMouseDownEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleMouseDownEvent(
														EventRecord&		aOSEvent)
{
	PRBool retVal = PR_FALSE;

	WindowPtr		whichWindow;
	short partCode = ::FindWindow(aOSEvent.where, &whichWindow);

	switch (partCode)
	{
		case inDrag:
		{
			Point macPoint;
#if TARGET_CARBON
			Rect portRect;
			::GetPortBounds(GetWindowPort(whichWindow), &portRect);
			macPoint = topLeft(portRect);
#else
			macPoint = topLeft(whichWindow->portRect);
#endif
			::LocalToGlobal(&macPoint);
			mTopLevelWidget->Move(macPoint.h, macPoint.v);
			break;
		}

		case inGrow:
		{
#if TARGET_CARBON
			Rect macRect;
			::GetWindowPortBounds ( whichWindow, &macRect );
#else
			Rect macRect = whichWindow->portRect;
#endif
			::LocalToGlobal(&topLeft(macRect));
			::LocalToGlobal(&botRight(macRect));
			mTopLevelWidget->Resize(macRect.right - macRect.left + 1, macRect.bottom - macRect.top + 1, PR_FALSE);
			break;
		}

		case inGoAway:
		{
			mTopLevelWidget->Destroy();
			break;
		}

		case inContent:
		{
			nsMouseEvent mouseEvent;
			ConvertOSEventToMouseEvent(aOSEvent, mouseEvent, NS_MOUSE_LEFT_BUTTON_DOWN);
			nsWindow* widgetHit = (nsWindow*)mouseEvent.widget;
			if (widgetHit)
			{
				// set the focus on the widget hit, if it accepts it
				if (widgetHit->AcceptFocusOnClick())
				{
					nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)widgetHit->GetToolkit()) );
					if (toolkit)
						toolkit->SetFocus(widgetHit);
				}

				// dispatch the event
				retVal = widgetHit->DispatchMouseEvent(mouseEvent);
			}

			if (mLastWidgetHit)
				mLastWidgetHit->RemoveDeleteObserver(this);

			mLastWidgetHit = widgetHit;
			mMouseInWidgetHit = PR_TRUE;

			if (mLastWidgetHit)
				mLastWidgetHit->AddDeleteObserver(this);
			break;
		}


		case inZoomIn:
		case inZoomOut:
		{
			// Now that we have found the partcode it is ok to actually zoom the window
			ZoomWindow(whichWindow, partCode, (whichWindow == FrontWindow()));
			
#if TARGET_CARBON
			Rect macRect;
			::GetWindowPortBounds(whichWindow, &macRect);
#else
			Rect macRect = whichWindow->portRect;
#endif
			::LocalToGlobal(&topLeft(macRect));
			::LocalToGlobal(&botRight(macRect));
			mTopLevelWidget->Resize(macRect.right - macRect.left, macRect.bottom - macRect.top, PR_FALSE);
			break;
		}
	}
	return retVal;
}


//-------------------------------------------------------------------------
//
// HandleMouseUpEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleMouseUpEvent(
														EventRecord&		aOSEvent)
{
	PRBool retVal = PR_FALSE;

	nsMouseEvent mouseEvent;
	ConvertOSEventToMouseEvent(aOSEvent, mouseEvent, NS_MOUSE_LEFT_BUTTON_UP);

	nsWindow* widgetReleased = (nsWindow*)mouseEvent.widget;
	if ((widgetReleased != nsnull) && (widgetReleased != mLastWidgetHit))
		retVal |= widgetReleased->DispatchMouseEvent(mouseEvent);

	if (mLastWidgetHit)
	{
		mLastWidgetHit->RemoveDeleteObserver(this);

		mouseEvent.widget = mLastWidgetHit;
		retVal |= mLastWidgetHit->DispatchMouseEvent(mouseEvent);

		mLastWidgetHit = nsnull;
	}

	return retVal;
}


//-------------------------------------------------------------------------
//
// HandleMouseMoveEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleMouseMoveEvent(
														EventRecord&		aOSEvent)
{
	PRBool retVal = PR_FALSE;

	nsMouseEvent mouseEvent;
	ConvertOSEventToMouseEvent(aOSEvent, mouseEvent, NS_MOUSE_MOVE);

	if (mLastWidgetHit)
	{
		Point macPoint = aOSEvent.where;
		::GlobalToLocal(&macPoint);
		PRBool inWidgetHit = mLastWidgetHit->PointInWidget(macPoint);
		if (inWidgetHit != mMouseInWidgetHit)
		{
			mouseEvent.message = (inWidgetHit ? NS_MOUSE_ENTER : NS_MOUSE_EXIT);
			mMouseInWidgetHit = inWidgetHit;
		}
		retVal |= mLastWidgetHit->DispatchMouseEvent(mouseEvent);
	}
	else
	{
		nsWindow* widgetPointed = (nsWindow*)mouseEvent.widget;
		if (widgetPointed != mLastWidgetPointed)
		{
			if (mLastWidgetPointed)
			{
				mLastWidgetPointed->RemoveDeleteObserver(this);

				mouseEvent.widget = mLastWidgetPointed;
					mouseEvent.message = NS_MOUSE_EXIT;
					retVal |= mLastWidgetPointed->DispatchMouseEvent(mouseEvent);
					mLastWidgetPointed = nsnull;
				mouseEvent.widget = widgetPointed;
			}

			if (widgetPointed)
			{
				widgetPointed->AddDeleteObserver(this);

				mLastWidgetPointed = widgetPointed;
				mouseEvent.message = NS_MOUSE_ENTER;
				retVal |= widgetPointed->DispatchMouseEvent(mouseEvent);
			}
		}
		else
		{
			if (widgetPointed)
				retVal |= widgetPointed->DispatchMouseEvent(mouseEvent);
		}
	}

	return retVal;
}


#pragma mark -
//-------------------------------------------------------------------------
//
// ConvertOSEventToMouseEvent
//
//-------------------------------------------------------------------------
void nsMacEventHandler::ConvertOSEventToMouseEvent(
														EventRecord&		aOSEvent,
														nsMouseEvent&		aMouseEvent,
														PRUint32				aMessage)
{
		static long		lastWhen = 0;
		static Point	lastWhere = {0, 0};
		static short	lastClickCount = 0;

	// get the click count
	if (((aOSEvent.when - lastWhen) < ::LMGetDoubleTime())
		&& (abs(aOSEvent.where.h - lastWhere.h) < 5)
		&& (abs(aOSEvent.where.v - lastWhere.v) < 5)) 
	{
		if (aOSEvent.what == mouseDown)
		{
			lastClickCount ++;
			if (lastClickCount == 2)
				aMessage = NS_MOUSE_LEFT_DOUBLECLICK;
		}
	}
	else
	{
		if (! ::StillDown())
			lastClickCount = 0;
	}
	lastWhen  = aOSEvent.when;
	lastWhere = aOSEvent.where;

	// get the widget hit and the hit point inside that widget
	Point hitPoint = aOSEvent.where;
#if TARGET_CARBON
	GrafPtr grafPort = reinterpret_cast<GrafPtr>(mTopLevelWidget->GetNativeData(NS_NATIVE_GRAPHIC));
	::SetPort(grafPort);
	Rect savePortRect;
	::GetPortBounds(grafPort, &savePortRect);
#else
	GrafPtr grafPort = static_cast<GrafPort*>(mTopLevelWidget->GetNativeData(NS_NATIVE_GRAPHIC));
	::SetPort(grafPort);
	Rect savePortRect = grafPort->portRect;
#endif
	::SetOrigin(0, 0);
	::GlobalToLocal(&hitPoint);
	::SetOrigin(savePortRect.left, savePortRect.top);
	nsPoint widgetHitPoint(hitPoint.h, hitPoint.v);

	// if the mouse button is still down, send events to the last widget hit
	nsWindow* widgetHit = nsnull;
	if (mLastWidgetHit)
	{
 		if (::StillDown() || aMessage == NS_MOUSE_LEFT_BUTTON_UP)
	 		widgetHit = mLastWidgetHit;
	 	else
	 	{
	 		// Patch: some widgets can eat mouseUp events (text widgets in TEClick, sbars in TrackControl).
	 		// In that case, fall back to the normal case.
	 		mLastWidgetHit->RemoveDeleteObserver(this);
	 		mLastWidgetHit = nsnull;
	 	}
	}

	if (! widgetHit)
		widgetHit = mTopLevelWidget->FindWidgetHit(hitPoint);

	if (widgetHit)
	{
		nsRect bounds;
		widgetHit->GetBounds(bounds);
		nsPoint widgetOrigin(bounds.x, bounds.y);
		widgetHit->LocalToWindowCoordinate(widgetOrigin);
		widgetHitPoint.MoveBy(-widgetOrigin.x, -widgetOrigin.y);
	}

	// nsEvent
	aMouseEvent.eventStructType = NS_MOUSE_EVENT;
	aMouseEvent.message		= aMessage;
	aMouseEvent.point			= widgetHitPoint;
	aMouseEvent.time			= PR_IntervalNow();

	// nsGUIEvent
	aMouseEvent.widget		= widgetHit;
	aMouseEvent.nativeMsg	= (void*)&aOSEvent;

	// nsInputEvent
	aMouseEvent.isShift		= ((aOSEvent.modifiers & shiftKey) != 0);
	aMouseEvent.isControl	= ((aOSEvent.modifiers & controlKey) != 0);
	aMouseEvent.isAlt			= ((aOSEvent.modifiers & optionKey) != 0);
	aMouseEvent.isCommand	= ((aOSEvent.modifiers & cmdKey) != 0);

	// nsMouseEvent
	aMouseEvent.clickCount = lastClickCount;
}

//-------------------------------------------------------------------------
//
// HandlePositionToOffsetEvent
//
//-------------------------------------------------------------------------
long nsMacEventHandler::HandlePositionToOffset(Point aPoint,short* regionClass)
{
	*regionClass = kTSMOutsideOfBody;
	return 0;
}

//-------------------------------------------------------------------------
//
// HandleOffsetToPosition Event
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleOffsetToPosition(long offset,Point* thePoint)
{
	(*thePoint).v = 0;
	(*thePoint).h = 0;
	return PR_TRUE;
}

//-------------------------------------------------------------------------
//
// HandleUpdate Event
//
//-------------------------------------------------------------------------
 nsMacEventHandler::HandleUpdateInputArea(char* text,Size text_size, ScriptCode textScript,long fixedLength,TextRangeArray* textRangeList)
{
	TextToUnicodeInfo	textToUnicodeInfo;
	TextEncoding		textEncodingFromScript;
	ByteCount			source_read;
	ByteOffset			sourceOffset[2], destinationOffset[2];
	ItemCount			destinationLength;
	nsTextRangeArray	xpTextRangeArray;
	PRBool				rv;
	int					i;
	OSErr				err;
	
	//
	// if we aren't in composition mode alredy, signal the backing store w/ the mode change
	//	
	if (!mIMEIsComposing) {
		mIMEIsComposing = PR_TRUE;
		HandleStartComposition();
	}

	//
	// convert our script code (smKeyScript) to a TextEncoding 
	//
	err = ::UpgradeScriptInfoToTextEncoding(textScript,kTextLanguageDontCare,kTextRegionDontCare,nsnull,
											&textEncodingFromScript);
	NS_ASSERTION(err==noErr,"nsMacEventHandler::UpdateInputArea: UpgradeScriptInfoToTextEncoding failed.");
	if (err!=noErr) { return PR_FALSE; }
	
	err = ::CreateTextToUnicodeInfoByEncoding(textEncodingFromScript,&textToUnicodeInfo);
	NS_ASSERTION(err==noErr,"nsMacEventHandler::UpdateInputArea: CreateUnicodeToTextInfoByEncoding failed.");
	if (err!=noErr) { return PR_FALSE; }

	
	if (mIMECompositionStringSize < text_size+32) {
		mIMECompositionStringSize = text_size+32;
		if (mIMECompositionString!=nsnull) delete [] mIMECompositionString;
		mIMECompositionString = new PRUnichar[mIMECompositionStringSize];
	}

	//
	// build up the nsGUIEvent text range array and convert the destination string to Unicode
	//
	if (textRangeList!=NULL) {
	
		xpTextRangeArray = new nsTextRange[textRangeList->fNumOfRanges];
		NS_ASSERTION(xpTextRangeArray!=NULL,"nsMacEventHandler::UpdateInputArea: xpTextRangeArray memory allocation failed.");
		if (xpTextRangeArray==NULL) { ::DisposeTextToUnicodeInfo(&textToUnicodeInfo); return PR_FALSE; }

		//
		// the TEC offset mapping capabilities won't work here because you need to have unique, ordered offsets
		//  so instead we iterate over the range list and map each range individually.  it's probably faster than
		//  trying to do collapse all the ranges into a single offset list
		//
		for(i=0;i<textRangeList->fNumOfRanges;i++) {			
			
			sourceOffset[0] = textRangeList->fRange[i].fStart;
			sourceOffset[1] = textRangeList->fRange[i].fEnd;
			
			err = ::ConvertFromTextToUnicode(textToUnicodeInfo,text_size,text,kUnicodeLooseMappingsMask,
							2,sourceOffset,&destinationLength,destinationOffset,
							mIMECompositionStringSize*sizeof(PRUnichar),
							&source_read,&mIMECompositionStringLength,mIMECompositionString);
			NS_ASSERTION(err==noErr,"nsMacEventHandler::UpdateInputArea: ConvertFromTextToUnicode failed.\n");
			if (err!=noErr) { ::DisposeTextToUnicodeInfo(&textToUnicodeInfo); return PR_FALSE; }
			
			if (destinationLength==2) {
				xpTextRangeArray[i].mStartOffset = destinationOffset[0]/sizeof(PRUnichar);
				xpTextRangeArray[i].mEndOffset = destinationOffset[1]/sizeof(PRUnichar);
				xpTextRangeArray[i].mRangeType = textRangeList->fRange[i].fHiliteStyle;
			} else {
				xpTextRangeArray[i].mStartOffset = destinationOffset[0]/sizeof(PRUnichar);
				xpTextRangeArray[i].mEndOffset = destinationOffset[0]/sizeof(PRUnichar);
				xpTextRangeArray[i].mRangeType = textRangeList->fRange[i].fHiliteStyle;
			}			
		}
	} else {

		err = ::ConvertFromTextToUnicode(textToUnicodeInfo,text_size,text,kUnicodeLooseMappingsMask,
						0,NULL,NULL,NULL,
						mIMECompositionStringSize*sizeof(PRUnichar),
						&source_read,&mIMECompositionStringLength,mIMECompositionString);
		NS_ASSERTION(err==noErr,"nsMacEventHandler::UpdateInputArea: ConvertFromTextToUnicode failed.\n");
		if (err!=noErr) { ::DisposeTextToUnicodeInfo(&textToUnicodeInfo); return PR_FALSE; }

		xpTextRangeArray = new nsTextRange[1];
		xpTextRangeArray[0].mStartOffset = 0;
		xpTextRangeArray[0].mEndOffset = (mIMECompositionStringLength/sizeof(PRUnichar));
		xpTextRangeArray[0].mRangeType = NS_TEXTRANGE_RAWINPUT;		
	}

	//
	// null terminate the string for the XP-stuff
	//
	mIMECompositionString[mIMECompositionStringLength/sizeof(PRUnichar)] = (PRUnichar)0;

	if (textRangeList==NULL)
		rv = HandleTextEvent(1,xpTextRangeArray);
	else
		rv = HandleTextEvent(textRangeList->fNumOfRanges,xpTextRangeArray);
		
	::DisposeTextToUnicodeInfo(&textToUnicodeInfo);
	
	//
	// text_size incldues the null-terminator which isn't included in the fixedLength
	//
	if (fixedLength==-1 || fixedLength==text_size-1) {
		HandleEndComposition();
		mIMEIsComposing = PR_FALSE;
	}
	
	return rv;
}

//-------------------------------------------------------------------------
//
// HandleStartComposition
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleStartComposition(void)
{
	// 
	// get the focused widget [tague: may need to rethink this later]
	//
	nsWindow* focusedWidget = mTopLevelWidget;	
	nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
	if (toolkit)
		focusedWidget = toolkit->GetFocus();
	
	if (!focusedWidget)
	{
  	NS_WARNING("Throwing away start composition event because there is no focused widget");
		return PR_FALSE;
	}
	
	//
	// create the nsCompositionEvent
	//
	nsCompositionEvent		compositionEvent;

	compositionEvent.eventStructType = NS_COMPOSITION_START;
	compositionEvent.message = NS_COMPOSITION_START;
	compositionEvent.point.x = 0;
	compositionEvent.point.y = 0;
	compositionEvent.time = PR_IntervalNow();

	//
	// nsGUIEvent parts
	//
	compositionEvent.widget	= focusedWidget;
	compositionEvent.nativeMsg	= (void*)nsnull;		// no native message for this

	return(focusedWidget->DispatchWindowEvent(compositionEvent));
}

//-------------------------------------------------------------------------
//
// HandleEndComposition
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleEndComposition(void)
{
	// 
	// get the focused widget [tague: may need to rethink this later]
	//
	nsWindow* focusedWidget = mTopLevelWidget;	
	nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
	if (toolkit)
		focusedWidget = toolkit->GetFocus();
	
	if (!focusedWidget)
	{
  	NS_WARNING("Throwing away end composition event because there is no focused widget");
		return PR_FALSE;
	}
	
	//
	// create the nsCompositionEvent
	//
	nsCompositionEvent		compositionEvent;

	compositionEvent.eventStructType = NS_COMPOSITION_END;
	compositionEvent.message = NS_COMPOSITION_END;
	compositionEvent.point.x = 0;
	compositionEvent.point.y = 0;
	compositionEvent.time = PR_IntervalNow();

	//
	// nsGUIEvent parts
	//
	compositionEvent.widget	= focusedWidget;
	compositionEvent.nativeMsg	= (void*)nsnull;		// no native message for this

	return(focusedWidget->DispatchWindowEvent(compositionEvent));
}

//-------------------------------------------------------------------------
//
// HandleTextEvent
//
//-------------------------------------------------------------------------
PRBool nsMacEventHandler::HandleTextEvent(PRUint32 textRangeCount, nsTextRangeArray textRangeArray)
{
	// 
	// get the focused widget [tague: may need to rethink this later]
	//
	nsWindow* focusedWidget = mTopLevelWidget;	
	nsCOMPtr<nsToolkit> toolkit ( dont_AddRef((nsToolkit*)mTopLevelWidget->GetToolkit()) );
	if (toolkit)
		focusedWidget = toolkit->GetFocus();
	
	if (!focusedWidget)
	{
  	NS_WARNING("Throwing away text event because there is no focused widget");
		return PR_FALSE;
	}
	
	//
	// create the nsCompositionEvent
	//
	nsTextEvent		textEvent;

	textEvent.eventStructType = NS_TEXT_EVENT;
	textEvent.message = NS_TEXT_EVENT;
	textEvent.point.x = 0;
	textEvent.point.y = 0;
	textEvent.time = PR_IntervalNow();
	textEvent.theText = mIMECompositionString;
	textEvent.rangeCount = textRangeCount;
	textEvent.rangeArray = textRangeArray;
	
	//
	// nsGUIEvent parts
	//
	textEvent.widget	= focusedWidget;
	textEvent.nativeMsg	= (void*)nsnull;		// no native message for this

	if (focusedWidget->DispatchWindowEvent(textEvent)==NS_OK) 
		return PR_TRUE;
	else 
		return PR_FALSE;
}
