/*	XGAppCore_mac.cpp
 *
 *		This is the Macintosh specific routiens that define the
 *	application core class.
 */

/*  YAAF - Yet another application framework
 *  Copyright (C) 1997, 1998 William Edward Woody
 *  
 *  This library is free software; you can redistribute it
 *  and/or modify it under the terms of the GNU Library
 *  General Public License as published by the Free Software
 *  Foundation; either version 2 of the License, or any
 *  later version.
 *  
 *  This library is distributed in the hope that it will be
 *  useful, but WITHOUT ANY WARRANTY; without even the implied
 *  warranty of MERCHANTABIILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE. See the GNU Library General Public License for
 *  more details.
 *  
 *  You should have received a copy of the GNU Library General
 *  Public License along with this library; if not, write to the
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 *  
 *  To contact the author, either e-mail me at woody@pandawave.com, 
 *	or write to
 *  
 *          William Edward Woody
 *          In Phase Consulting
 *          1545 Ard Eevin Avenue
 *          Glendale, CA 91202
 *
 *	Or visit us on the web at http://www.pandawave.com
 */

#include <XApplication.h>
#include <XWindow.h>
#include <XMessages.h>
#include <XMenu.h>
#include <XError.h>
#include <XModifiers.h>
#include <XDataUtil.h>
#include <XCursorUtil.h>
#include <XThread.h>
#include "MacFloater.h"

/************************************************************************/
/*																		*/
/*	Globals																*/
/*																		*/
/************************************************************************/

static AEEventHandlerUPP	GAppleEventProc;

/************************************************************************/
/*																		*/
/*	Common Internals													*/
/*																		*/
/************************************************************************/

#pragma mark Initialization and Shutdown

/*	XGAppCore::InitOS
 *
 *		Initialize the operating system. This just does the basic
 *	initialization without the frills. This only gets run once.
 */

void XGAppCore::InitOS()
{
	long flags;
	int i;
	static bool gInit = false;
		
	if (gInit) return;					// run this only once.
	gInit = true;
	
	/*
	 *	Core startup
	 */
	
	::InitGraf(&qd.thePort);
	::InitFonts();
	::InitWindows();
	::InitMenus();
	::TEInit();
	::InitDialogs(NULL);
	::InitCursor();
	
	/*
	 *	Flush events
	 */
	
	::FlushEvents(everyEvent,0);
	
	/*
	 *	Set the stack size to 32K (on the 68K Macintosh), if available
	 */
	
#ifndef __powerc
	::SetApplLimit(GetApplLimit() - 32768L);
#endif

	/*
	 *	And add more memory master pointers
	 */
	
	for (i = 0; i < 5; i++) ::MoreMasters();
	::MaxApplZone();
		
	/*
	 *	Now query for different attributes
	 */
	
	fAppleEvents = false;
	if (!Gestalt(gestaltAppleEventsAttr,&flags)) {
		if (flags & 1) fAppleEvents = true;
	}
	
	if (fAppleEvents) {
		GAppleEventProc = NewAEEventHandlerProc(AEHandleProc);
		
		::AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,GAppleEventProc,0,false);
		::AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,GAppleEventProc,0,false);
		::AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,GAppleEventProc,0,false);
		::AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,GAppleEventProc,0,false);
	}
}

/*	XGAppCore::KillOS
 *
 *		Kill the operating system stuff
 */

void XGAppCore::KillOS()
{
	if (fAppleEvents) {
		DisposeRoutineDescriptor(GAppleEventProc);
	}
}

/*	XGAppCore::GetAppArgs
 *
 *		This is called just before the event pump is started on the
 *	Macintosh.
 */

void XGAppCore::GetAppArgs()
{
	if (fAppleEvents) {
	} else {
		InitOS6Events();
	}
}

/************************************************************************/
/*																		*/
/*	Event Pump Window Support											*/
/*																		*/
/************************************************************************/

#pragma mark -
#pragma mark Window Support

/*	XGAppCore::GetWindowMinMax
 *
 *		Find the minimum, maximum window sizes
 */

void XGAppCore::GetWindowMinMax(WindowPtr w, Rect *r)
{
	Point pt;
	XGWindow *tw = XGWindow::GetXGWindow(w);
	
	if (tw == NULL) {
		SetRect(r,75,75,4096,4096);
	} else {
		pt = tw->MinWindowSize();
		if (pt.h == 0) pt.h = 75;
		if (pt.v == 0) pt.v = 75;
		r->left = pt.h;
		r->top = pt.v;
		
		pt = tw->MaxWindowSize();
		if (pt.h == 0) pt.h = 4096;
		if (pt.v == 0) pt.v = 4096;
		r->right = pt.h;
		r->bottom = pt.v;
	}
}

/*	XGAppCore::SetWindowZoom
 *
 *		Set the zoom rectangle for this window to the maximum
 *	zoom size.
 */

void XGAppCore::SetWindowZoom(WindowPtr w)
{
	Point pt;
	XGWindow *tw;
	WStateData **wHandle;
	
	tw = XGWindow::GetXGWindow(w);
	if (tw == NULL) return;
	pt = tw->ZoomWindowSize();				// zoom window size
	
	wHandle = (WStateData **)(((WindowPeek)w)->dataHandle);
	if (pt.h != 0) (**wHandle).stdState.right = (**wHandle).stdState.left + pt.h;
	if (pt.v != 0) (**wHandle).stdState.bottom = (**wHandle).stdState.top + pt.v;
}

/*	XGAppCore::DrawGrowIcon
 *
 *		Draw the grow icon in this window
 */

void XGAppCore::DrawGrowIcon(WindowPtr w)
{
	Rect r;
	
	::SetPort(w);
	::SetOrigin(0,0);
	r = w->portRect;
	r.top = r.bottom - 15;
	r.left = r.right - 15;
	::ClipRect(&r);
	::DrawGrowIcon(w);
}

/************************************************************************/
/*																		*/
/*	Event Translation													*/
/*																		*/
/************************************************************************/

#pragma mark -
#pragma mark Keyboard Translation

/*	XGAppCore::GetEventFlags
 *
 *		This formulates the modifier flag bit field depending on the
 *	current event
 */

short XGAppCore::GetEventFlags(EventRecord &e)
{
	short flags = 0;
	
	if (e.modifiers & shiftKey)			flags |= KKeyShift;
	if (e.modifiers & controlKey)		flags |= KKeyControl;
	if (e.modifiers & cmdKey)			flags |= KKeyCommand;
	if (e.modifiers & optionKey)		flags |= KKeyOption;
	if (e.modifiers & btnState)			flags |= KKeyButton;
	
	if ((e.what == keyDown) || (e.what == autoKey)) {
		char key;
		
		key = (char)(e.message);
		switch (key) {
			case 0x1C: case 0x1D: case 0x1E: case 0x1F:
			case 0x0B: case 0x0C: case 0x01: case 0x04:
			case 0x1B: case 0x7F:
			case 0x05: case 0x10:
				flags |= KSpecialKey;
		}
	}
	
	gLastMods = flags;					// remember this...
	return flags;
}

/*	XGAppCore::GetKeyCode
 *
 *		Get the keyboard character code
 */

short XGAppCore::GetKeyCode(EventRecord &e)
{
	char key;
	char code;
	
	key = (char)(e.message);
	code = (char)(e.message >> 8);
	
	switch (key) {
		case 0x1C: 
			return KKeyLeftCursor;
		case 0x1D: 
			return KKeyRightCursor;
		case 0x1E: 
			return KKeyUpCursor;
		case 0x1F:
			return KKeyDownCursor;
		case 0x0B: 
			return KKeyPageUp;
		case 0x0C: 
			return KKeyPageDown;
		case 0x01: 
			return KKeyHome;
		case 0x04:
			return KKeyEnd;
		case 0x1B: 
			if (code == 0x47) return KKeyClear;
			return KKeyEscape;
		case 0x03:
		case 0x0D: 
			return 0x0D;					// return key
		case 0x7F:
			return KKeyDelete;
		case 0x05:
			return KKeyHelp; 
		case 0x10:
			switch (code) {
				case 0x7A:		return KKeyF1;
				case 0x78:		return KKeyF2;
				case 0x63:		return KKeyF3;
				case 0x76:		return KKeyF4;
				case 0x60:		return KKeyF5;
				case 0x61:		return KKeyF6;
				case 0x62:		return KKeyF7;
				case 0x64:		return KKeyF8;
				case 0x65:		return KKeyF9;
				case 0x6D:		return KKeyF10;
				case 0x67:		return KKeyF11;
				case 0x6F:		return KKeyF12;
				case 0x69:		return KKeyF13;
				case 0x6B:		return KKeyF14;
				case 0x71:		return KKeyF15;
				default:		return key;
			}
		default:
			return key;						// normal key
	}
}

/************************************************************************/
/*																		*/
/*	Finder/Apple Events													*/
/*																		*/
/************************************************************************/

#pragma mark -
#pragma mark Finder Events

/*	XGAppCore::InitOS6Events
 *
 *		If I'm running on MacOS6, this gets the files
 */

void XGAppCore::InitOS6Events()
{
#ifndef __powerc							// only on 68K macs
	short what,count;
	short index;
	AppFile file;
	FSSpec fdata;
	
	::CountAppFiles(&what,&count);
	if (count == 0) {
		GetCurFocus()->SendDispatch(KXGOpenApplication,0,NULL);
	} else {
		for (index = 1; index <= count; index++) {
			::GetAppFiles(index,&file);
			fdata.vRefNum = file.vRefNum;
			fdata.parID = 0;
			pstrcpy(fdata.name,file.fName);
			if (what == 0) {
				GetCurFocus()->SendDispatch(KXGOpenDocument,0,(void *)&fdata);
			} else {
				GetCurFocus()->SendDispatch(KXGPrintDocument,0,(void *)&fdata);
			}
		}
		
		if (what == 1) {
			GetCurFocus()->SendDispatch(KXGQuitApplication,0,NULL);
		}
	}
#endif
}

/*	XGAppCore::GotRequiredParams
 *
 *		Check to see all the required parameters were fetched
 */

OSErr XGAppCore::GotRequiredParams(AppleEvent *event)
{
	OSErr myErr;
	long size;
	DescType returnType;
	
	myErr = AEGetAttributePtr(event,keyMissedKeywordAttr,typeWildCard,&returnType,NULL,0,&size);
	if (myErr == noErr) return errAEParamMissed;
	else if (myErr == errAEDescNotFound) return noErr;
	else return myErr;
}

/*	XGAppCore::AEHandleProc
 *
 *		This is the code to handle the Apple Events for MacOS7 and later
 */

pascal OSErr XGAppCore::AEHandleProc(AppleEvent *event, AppleEvent */*ret*/, long)
{
	OSErr myErr;
	long eClass,eType;
	DescType returnType;
	long size;
	long off,len;
	AEDescList docList;
	AEKeyword keyWord;
	FSSpec file;
	
	/*
	 *	Get the Apple Event message type
	 */
	
	if (noErr != (myErr = AEGetAttributePtr(event,keyEventClassAttr,typeType,&returnType,(Ptr)&eClass,sizeof(eClass),&size))) return myErr;
	if (noErr != (myErr = AEGetAttributePtr(event,keyEventIDAttr,typeType,&returnType,(Ptr)&eType,sizeof(eType),&size))) return myErr;
	
	/*
	 *	We've now got the class and type of the event. Dispatch for the
	 *	common four entry points.
	 */
	
	if (eClass == kCoreEventClass) {
		switch (eType) {
			case kAEOpenApplication:
				/*
				 *	New application event
				 */
				
				myErr = GotRequiredParams(event);
				if (myErr == noErr) {				// new file
					XGAppCore::GetApplication()->
						GetCurFocus()->
						SendDispatch(KXGOpenApplication,0,NULL);
				}
				return myErr;
			case kAEOpenDocuments:
				/*
				 *	Open new documents
				 */
				
				if (noErr != (myErr = AEGetParamDesc(event,keyDirectObject,typeAEList,&docList))) return myErr;
				if (noErr != (myErr = AECountItems(&docList,&len))) {
					AEDisposeDesc(&docList);
					return myErr;
				}
				for (off = 1; off <= len; off++) {
					if (noErr != (myErr = AEGetNthPtr(&docList,off,typeFSS,&keyWord,&returnType,(Ptr)&file,sizeof(file),&size))) {
						AEDisposeDesc(&docList);
						return myErr;
					}
					
					XGAppCore::GetApplication()->
						GetCurFocus()->
						SendDispatch(KXGOpenDocument,0,(void *)&file);
				}
				AEDisposeDesc(&docList);
				break;
			case kAEPrintDocuments:
				/*
				 *	Print specified documents
				 */
				
				if (noErr != (myErr = AEGetParamDesc(event,keyDirectObject,typeAEList,&docList))) return myErr;
				if (noErr != (myErr = AECountItems(&docList,&len))) {
					AEDisposeDesc(&docList);
					return myErr;
				}
				for (off = 1; off <= len; off++) {
					if (noErr != (myErr = AEGetNthPtr(&docList,off,typeFSS,&keyWord,&returnType,(Ptr)&file,sizeof(file),&size))) {
						AEDisposeDesc(&docList);
						return myErr;
					}
					
					XGAppCore::GetApplication()->
						GetCurFocus()->
						SendDispatch(KXGPrintDocument,0,(void *)&file);
				}
				AEDisposeDesc(&docList);
				break;
			case kAEQuitApplication:
				/*
				 *	Quit this application
				 */
				
				myErr = GotRequiredParams(event);
				if (myErr == noErr) {
					if (-1 == XGAppCore::GetApplication()->
								  GetCurFocus()->
								  SendDispatch(KXGQuitApplication,0,NULL)) {
						return 1;
					} else {
						return noErr;
					}
				} else return myErr;
			default:
				return errAEEventNotHandled;			// Not able to handle event
		}
	
		return GotRequiredParams(event);				// Fall through to handle this		
	}
	
	/*
	 *	Process the rest of the possible events
	 */
	
	return errAEEventNotHandled;
}

/*	XGAppCore::InitAppleEvents
 *
 *		Initialize apple events
 */

void XGAppCore::InitAppleEvents(void)
{
}

/************************************************************************/
/*																		*/
/*	Application Event Pump												*/
/*																		*/
/************************************************************************/

#pragma mark -
#pragma mark Event Pump and Dispatch

/*	XGAppCore::DoMenuKey
 *
 *		Handle the keyboard menu event
 */

bool XGAppCore::DoMenuKey(char c)
{
	return GetCurMenu()->MenuKey(GetCurFocus(),c);
}

/*	XGAppCore::DoMenuClick
 *
 *		Handle the mouse in menu event
 */

void XGAppCore::DoMenuClick(Point pt)
{
	GetCurMenu()->MenuSelect(GetCurFocus(),pt.h,pt.v);
}

/*	XGAppCore::DoWindowKey
 *
 *		Handle keyboard event that is being sent to a window.
 */

void XGAppCore::DoWindowKey(EventRecord &e)
{
	short event;
	short key;
	
	event = GetEventFlags(e);
	key   = GetKeyCode(e);
	
	if (event & KKeyCommand) {
		GetCurFocus()->SendDispatch(KXGMenuKey,
									MAKEDWORD(event,key),
									NULL);
	} else {
		GetCurFocus()->SendDispatch(KXGKeyEvent,
									MAKEDWORD(event,key),
									NULL);
	}
}

/*	XGAppCore::DoActivate
 *
 *		Handle activate event. This sends the activation/deactivation
 *	events
 */

void XGAppCore::DoActivate(WindowPtr w, bool flag)
{
	XGWindow *tw;
	
	tw = XGWindow::GetXGWindow(w);
	if (tw) {
		tw->DoActivate(flag);
		if (!(tw->GetWindowAttributes() & KAttrNoResize)) {
			DrawGrowIcon(w);
		}
	}
}

/*	XGRDoActivate
 *
 *		Insert this into my pump
 */

void XGRDoActivate(WindowPtr w, short f)
{
	XGAppCore::GetApplication()->DoActivate(w,f);
}

/*	XGAppCore::DoUpdate
 *
 *		Find the bounding rectangle for the update region of my
 *	window, and send the update event
 */

void XGAppCore::DoUpdate(WindowPtr w)
{
	RgnHandle rgn;
	Rect r;
	XGWindow *tw;
	Point p;
	
	/*
	 *	Force a reset of the window
	 */
	
	::SetPort(w);
	::SetOrigin(0,0);
	::ClipRect(&(w->portRect));
	
	/*
	 *	Now get the update rectangle
	 */
	
	rgn = ((WindowPeek)w)->updateRgn;
	r = (**rgn).rgnBBox;
	
	/*
	 *	And convert it to window coordinates
	 */
	
	p.h = r.left;
	p.v = r.top;
	GlobalToLocal(&p);
	r.left = p.h;
	r.top = p.v;
	p.h = r.right;
	p.v = r.bottom;
	GlobalToLocal(&p);
	r.right = p.h;
	r.bottom = p.v;
	
	/*
	 *	Now handle the udpate event
	 */
	
	tw = XGWindow::GetXGWindow(w);
	
	::BeginUpdate(w);
	if (tw) {
		if (!(tw->GetWindowAttributes() & KAttrNoResize)) {
			DrawGrowIcon(w);
		}
		tw->DoDraw(r);
		if (!(tw->GetWindowAttributes() & KAttrNoResize)) {
			DrawGrowIcon(w);
		}
	}
	::EndUpdate(w);
}

/*	XGAppCore::DoSizeContents
 *
 *		Handle the resize of the content region of this window
 */

void XGAppCore::DoSizeContents(WindowPtr w)
{
	XGWindow *tw;
	
	tw = XGWindow::GetXGWindow(w);
	if (tw) tw->DoSizeWindow();
}

/*	XGAppCore::DoMouseMove
 *
 *		Handle mouse motions when the mouse is not down
 */

void XGAppCore::DoMouseMove(EventRecord &e)
{
	short i;
	WindowPtr w;
	XGWindow *tw;
	Point pt;
	short flags;
		
	i = FindWindow(e.where,&w);
	if (i == inContent) {
		if ((w == ::MFrontWindow()) || (w == ::FrontWindow())) {
			tw = XGWindow::GetXGWindow(w);
			pt = e.where;
			flags = GetEventFlags(e);
					
			::SetPort(w);
			::SetOrigin(0,0);
			::GlobalToLocal(&pt);
			
			tw->DoMouseMove(pt,flags,NULL);
			return;
		}
	}
	::SetCursorID(KNormalCursor);
}

/*	XGAppCore::DoWindowClick
 *
 *		Handle window click event
 */

void XGAppCore::DoWindowClick(WindowPtr w, EventRecord &e)
{
	Point pt;
	XGWindow *tw;
	short flags;
	XGView *capture;
	
	/*
	 *	Get the XGWidnow pointer
	 */
	
	tw = XGWindow::GetXGWindow(w);
	if (tw == NULL) return;
	
	/*
	 *	Get the location of the mouse
	 */
	
	pt = e.where;
	::SetPort(w);
	::GlobalToLocal(&pt);
	pt.h -= w->portRect.left;
	pt.v -= w->portRect.top;
	
	/*
	 *	Get the status flags
	 */
	
	flags = GetEventFlags(e);
	
	/*
	 *	Screen for double click
	 */
	
	if (fLastTime + ::GetDblTime() >= ::TickCount()) {
		Rect r;
		
		r.left = fLastClick.h - 3;
		r.right = fLastClick.h + 3;
		r.top = fLastClick.v - 3;
		r.bottom = fLastClick.v + 3;
		
		if (PtInRect(pt,&r)) flags |= KDoubleClick;
	}
	
	/*
	 *	Send the event and spin if the mouse is captured
	 */
	
	if (NULL != (capture = tw->DoMouseDown(pt,flags))) {
		flags |= KCapturedMouse;
		
		while (::StillDown()) {
			RunUpdateOnce();
			
			::SetPort(w);
			::GetMouse(&pt);
			pt.h -= w->portRect.left;
			pt.v -= w->portRect.top;
			
			tw->DoMouseMove(pt,flags,capture);
		}
			
		::SetPort(w);
		::GetMouse(&pt);
		pt.h -= w->portRect.left;
		pt.v -= w->portRect.top;
		
		tw->DoMouseUp(pt,flags,capture);
	}
	
	/*
	 *	Remember the last mouse down location
	 */
	
	fLastTime = ::TickCount();
	fLastClick = pt;
}


/*	XGAppCore::DoCloseWindow
 *
 *		Handle the window close event
 */

void XGAppCore::DoCloseWindow(WindowPtr w)
{
	short type;
	XGWindow *tw;
	
	type = ((WindowPeek)w)->windowKind;
	if (type < 0) {
		/*
		 *	Close desk accessory
		 */
		
		CloseDeskAcc(type);
	} else {
		tw = XGWindow::GetXGWindow(w);
		Assert(tw != NULL);						// it's not mine???
		tw->CloseWindow();
	}
}

/*	XGAppCore::DoMouseClick
 *
 *		Handle mouse down event by figuring out where this happened
 */

void XGAppCore::DoMouseClick(EventRecord &e)
{
	short i;
	WindowPtr w;
	Rect r;
	long l;
	bool flag;
	XGWindow *tw;
	
	w = NULL;
	i = ::FindWindow(e.where,&w);
	tw = XGWindow::GetXGWindow(w);
	switch (i) {
		case inDesk:
			break;
		case inMenuBar:
			DoMenuClick(e.where);
			break;
		case inSysWindow:				// click in system window
			::SystemClick(&e,w);
			break;
		case inContent:					// click in content region of window
			if (fModalWindow) {
				if (tw == fModalWindow) {
					DoWindowClick(w,e);
				}
				break;
			}
			if ((w != ::MFrontWindow()) && (w != ::FrontWindow())) {
				MSelectWindow(w);	// modal dialog support
			} else {
				DoWindowClick(w,e);
			}
			break;
		case inDrag:
			if (fModalWindow) {
				if (tw != fModalWindow) break;
			}
			::SetRect(&r,-16384,-16384,16384,16384);
			::MDragWindow(w,e.where,&r);
			break;
		case inGrow:
			if (fModalWindow) {
				if (tw != fModalWindow) break;
			}
			GetWindowMinMax(w,&r);
			l = ::GrowWindow(w,e.where,&r);
			if (l) {
				::SizeWindow(w,(short)l,(short)(l >> 16),false);
				::SetPort(w);
				::InvalRect(&(w->portRect));
				DoSizeContents(w);
			}
			break;
		case inGoAway:
			if (fModalWindow) {
				if (tw != fModalWindow) break;
			}
			flag = ::TrackGoAway(w,e.where);
			if (flag) DoCloseWindow(w);
			break;
		case inZoomIn:
		case inZoomOut:
			if (fModalWindow) {
				if (tw != fModalWindow) break;
			}
			SetWindowZoom(w);
			flag = ::TrackBox(w,e.where,i);
			if (flag) {
				::SetPort(w);
				::EraseRect(&(w->portRect));
				::ZoomWindow(w,i,true);
				::InvalRect(&(w->portRect));
				DoSizeContents(w);
			}
			break;
	}
}

/*	XGAppCore::DoEvent
 *
 *		Run the event loop pump.
 */

void XGAppCore::DoEvent()
{
	EventRecord event;
	RgnHandle rgn;
	Point pt;
	Rect r;
	unsigned long wneTime = ::GetCaretTime();
	
	/*
	 *	If we have several threads running, we need to yield as much
	 *	CPU to those threads as we can get away with, without degrading
	 *	the performance of the MacOS app.
	 */

	if (XGThread::GetThreadCount() > 1) {
		unsigned long tickcount;
		
		wneTime = 1;						// minimize time in WaitNextEvent
		tickcount = ::TickCount() + 10;		// give 1/6th second to other threads
		while (tickcount >= ::TickCount()) {
			GYieldThread = true;			// does everyone else want to give up
			XGThread::YieldThread(true);	// their timeslice? If so, screw this.
			if (GYieldThread) break;		// and give up time to MacOS system.
		}
	}
	
	/*
	 *	Find the move mouse region
	 */
	
	::GetMouse(&pt);
	::LocalToGlobal(&pt);
	rgn = ::NewRgn();
	::SetRect(&r,pt.h,pt.v,pt.h+1,pt.v+1);
	::RectRgn(rgn,&r);
	
	/*
	 *	Now poll for events. The region I set up will give me
	 *	null events if the mouse ever moves
	 */
	
	::WaitNextEvent(everyEvent,&event,wneTime,rgn);
	::DisposeRgn(rgn);
	
	/*
	 *	Send the event event
	 */
	
	if (1 == GetCurFocus()->SendDispatch(KXGAppEvent,0,(void *)&event)) {
		/* Event was processed. Bail */
		return;
	}
	
	/*
	 *	Now process the event
	 */
	
	switch (event.what) {
		case mouseDown:
			DoMouseClick(event);
			break;
		case keyDown:
			if (event.modifiers & cmdKey) {
				if (DoMenuKey((char)event.message)) break;
			}
			/* Fall through to */
		case autoKey:
			DoWindowKey(event);
			break;
		case updateEvt:
			DoUpdate((WindowPtr)(event.message));
			break;
		case osEvt:
			if (0x01 == (unsigned char)(event.message >> 24)) {
				/* Application suspend/resume */
				if (event.message & 0x01) {
					DoActivate(MFrontWindow(),true);
				} else {
					DoActivate(MFrontWindow(),false);
				}
			}
			break;
		case activateEvt:
//			DoActivate((WindowPtr)(event.message),
//					   (event.modifiers & 1) ? true : false);
			break;
			
		case kHighLevelEvent:
			if (fAppleEvents) {
				AEProcessAppleEvent(&event);
			}
			break;
		
		default:
			DoMouseMove(event);
			break;
	}
	
	/* Make sure menu bar is cleaned up */
	::HiliteMenu(0);
}

/*	XGAppCore::RunUpdateOnce
 *
 *		This runs the event loop once for update events onnly
 */

void XGAppCore::RunUpdateOnce(void)
{
	EventRecord event;
	
	::WaitNextEvent(everyEvent,&event,1,NULL);
	
	/*
	 *	Send the event event
	 */
	 
	if (1 == GetCurFocus()->SendDispatch(KXGAppEvent,0,(void *)&event)) {
		/* Event was processed. Bail */
		return;
	}
	
	/*
	 *	Now process the update event only.
	 */
	
	switch (event.what) {
		case updateEvt:
			DoUpdate((WindowPtr)(event.message));
			break;
	}
	
	/* Make sure menu bar is cleaned up */
	::HiliteMenu(0);
}

/*	XGAppCore::CancelCheck
 *
 *		This runs the event loop once for update events onnly
 */

bool XGAppCore::CancelCheck(void)
{
	bool status = false;
	EventRecord event;
	
	::WaitNextEvent(everyEvent,&event,1,NULL);
	
	/*
	 *	Send the event event
	 */
	 
	if (1 == GetCurFocus()->SendDispatch(KXGAppEvent,0,(void *)&event)) {
		/* Event was processed. Bail */
		return false;
	}
	
	/*
	 *	Now process the update event only.
	 */
	
	switch (event.what) {
		case updateEvt:
			DoUpdate((WindowPtr)(event.message));
			break;
		case keyDown:
			if (((event.modifiers & cmdKey) != 0) &&
					((event.message & charCodeMask) == '.'))
				status = true;
			break;
	}
	
	/* Make sure menu bar is cleaned up */
	::HiliteMenu(0);
	return status;
}
