/*********************************************************/
/* This source code copyright (c) 1991-2001, Aaron Giles */
/* See the Read Me file for licensing information.       */
/* Contact email: mac@aarongiles.com                     */
/*********************************************************/

//=====================================================================================
// Generic includes for Macintosh headers
//=====================================================================================

#if THINK_C
#include "THINK.Header"
#elif applec
#pragma load ":Headers:MPW.Header"
#elif __MWERKS__
//#include "MW.Header"
#else
#include "JPEGView.h"
#endif

//=====================================================================================
// Includes specific to this module
//=====================================================================================

#include "EventHandlers.h"

//=====================================================================================
// Global variables local to this module
//=====================================================================================

static Boolean gDrawMenuBar = true;
static long gLastEventWhen = 0L;

//=====================================================================================
// Prototypes for functions local to this module
//=====================================================================================

static void UpdateFastImages(void);
static void UpdateNextSlowImage(void);
static void UnhideWindows(void);

//=====================================================================================
// void MainEventLoop(void)
//=====================================================================================
// Serves as the main event loop for the application.
//=====================================================================================

extern void MainEventLoop(void) 
{
	Boolean isNullEvent, isDialogEvent;
	MonitorHandle theMonitor;
	EventRecord theEvent;
	RgnHandle mouseRgn;

	if (!(mouseRgn = NewRgn())) FatalError(errNoMemory);
	while (!gDone) {
		
		// ensure we are pointing to a valid *onscreen* port
		MySetPort((CGrafPtr)FWFrontWindow());
		UpdateCursor(mouseRgn);

		// verify our monitor configuration, and update affected images
		while (theMonitor = MonitorChanged()) UpdateImages(theMonitor);

		// identify the next event and dispatch it appropriately
		isNullEvent = !WaitNextEvent(everyEvent, &theEvent, kSleepTime, mouseRgn);
		isDialogEvent = FWIsDialogEvent(&theEvent);
		UpdateCursor(mouseRgn);
		if (isNullEvent) {
			DialogPtr theDialog;
			short itemHit;
			theDialog = FWFrontWindow();
			if (theDialog && WindowKind(theDialog) == dialogKind) 
				FWDialogSelect(&theEvent, &theDialog, &itemHit);
			HandleNullEvent();
		} else DispatchMainEvent(&theEvent, isDialogEvent);

		// handle any selections from the menu that pertain to the slide show
		if (gSlideShow && gPendingButton != -1) {
			if ((*gSlideOptions)->userControl) 
				gSlideShow = HandleUserControlButton(gPendingButton);
			else gSlideShow = HandleAutomaticButton(gPendingButton);
			if (!gSlideShow) CleanUpSlideShow();
		}

		// if we're in screen saver mode and the slide show ended, quit now
		if (gScreenSaver) {
			if (!gSlideShow) gDone = true;
			else EnsureFrontmost();
		}

		// if we've invalidated the menu bar, redraw it now
		if (gDrawMenuBar) {
			AdjustMenus();
			if (gMenuVisible) DrawMenuBar();
			gDrawMenuBar = false;
		}
	}
}

//=====================================================================================
// void MyInvalMenuBar(void)
//=====================================================================================
// Invalidate the menu bar area, so we draw it before taking the next event.
//=====================================================================================

extern void MyInvalMenuBar(void)
{
	gDrawMenuBar = true;
}

//=====================================================================================
// void DispatchMainEvent(EventRecord *theEvent, Boolean isDialogEvent)
//=====================================================================================
// Dispatches events from the main event loop.
//=====================================================================================

extern void DispatchMainEvent(EventRecord *theEvent, Boolean isDialogEvent)
{
	switch (theEvent->what) {
		case mouseDown:
			// if we're in screen saver mode, always abort
			if (gSlideShow && gScreenSaver) SendQuitApplication();
			else if (isDialogEvent) HandleMouseDownDialog(theEvent);
			else HandleMouseDownEvent(theEvent);
			break;
		case keyDown:
			if (theEvent->message == kCreator) break;
		case autoKey:
			if (gSlideShow && gScreenSaver) SendQuitApplication();
			else if (isDialogEvent) HandleKeyDownDialog(theEvent);
			else HandleKeyDownEvent(theEvent);
			break;
		case activateEvt:
			if (isDialogEvent) HandleActivateDialog(theEvent);
			else HandleActivateEvent(theEvent);
			break;
		case updateEvt:
			if (isDialogEvent) HandleUpdateDialog(theEvent);
			else HandleUpdateEvent(theEvent);
			break;
		case osEvt:
			HandleOSEvent(theEvent);
			break;
		case diskEvt:
			HandleDiskEvent(theEvent);
			break;
		case kHighLevelEvent:
			AEProcessAppleEvent(theEvent);
			break;
	}
}

//=====================================================================================
// void HandleNullEvent(void)
//=====================================================================================
// Handles null events.
//=====================================================================================

extern void HandleNullEvent(void) 
{
	static long gOldCount = 0L;
	ImageHandle theImage = FrontImage();
	long newCount = TickCount();
	Point point = { 0, 0 };

	// if balloon help is on, say the magic words for the appropriate window
	if (HMGetBalloons()) DispatchBalloonHelp();
	
	// scroll the credits
	IdleCredits();
		
	// if the frontmost image has a selection, animate it
	if (!gSlideShow && !gInBackground && theImage) {
		if ((newCount - gOldCount) >= (kSelRectSpeed / 2)) {
			gOldCount = newCount;
			AnimateAnts((*theImage)->ants);
		}
	}
	
	// if there's a slide show going on, update the slide show timers
	if (gSlideShow == kRunning) {
		HandleSlideNullEvent();
		if (gDone) return;
	}
	
	// update any pending windows that have associated gworlds
	UpdateFastImages();
	
	// if there's been sufficient delay, update the next pending window
	if ((newCount - gLastEventWhen) > kUpdateDelay && 
				(!gInBackground || gThePrefs.updateBack)) UpdateNextSlowImage();
}

//=====================================================================================
// void EnsureFrontmost(void)
//=====================================================================================
// Ensure that we are the frontmost application.
//=====================================================================================

extern void EnsureFrontmost(void)
{
	ProcessSerialNumber currentProcess, frontProcess;
	ProcessInfoRec theInfo;
	
	theInfo.processInfoLength = sizeof(ProcessInfoRec);
	theInfo.processName = nil;
	theInfo.processAppSpec = nil;
	GetFrontProcess(&frontProcess);
	GetProcessInformation(&frontProcess, &theInfo);
	if (theInfo.processSignature != kDarksideCreator &&
				theInfo.processSignature != kCreator) {
		GetCurrentProcess(&currentProcess);
		SetFrontProcess(&currentProcess);
	}
}

//=====================================================================================
// void DispatchBalloonHelp(void)
//=====================================================================================
// Determines whether we should pop up some balloons, and calls the appropriate handler
// routine.
//=====================================================================================

extern void DispatchBalloonHelp(void)
{
	Point mouseLoc = GlobalMouse();
	WindowPtr theWindow;
	long refCon;
	short part;

	part = FindWindow(mouseLoc, &theWindow);
	refCon = GetWRefCon(theWindow);
	if ((part == inContent || part == inGrow) && WindowHilited(theWindow)) {
		switch (refCon) {
			case kCommentsWindowID:
				DoCommentsHelp(mouseLoc);
				break;
			case kColorsWindowID:
				DoColorsHelp(mouseLoc);
				break;
			case kStatWindowID:
				DoStatsHelp(mouseLoc);
				break;
			case kSlideControlsWindowID:
				DoSlideControlsHelp(mouseLoc);
				break;
			case kImageWindowID:
				if (theWindow != GetSlideBackWindow()) DoImageHelp(theWindow, mouseLoc);
				break;
			case kHelpWindowID:
				DoHelpHelp(mouseLoc);
				break;
		}
	}
}

//=====================================================================================
// void UpdateFastImages(void)
//=====================================================================================
// Traverses the window list in search of images that can be updated quickly.
//=====================================================================================

static void UpdateFastImages(void)
{
	WindowPtr theWindow, frontWindow = FWFrontWindow();
	ImageHandle theImage;

	for (theWindow = frontWindow; theWindow; theWindow = NextWindow(theWindow)) {
		if ((theImage = FindImage(theWindow)) && !EmptyRgn((*theImage)->update)) {
			if (theWindow == frontWindow && !gInBackground && !Aborted(theImage))
				UpdateImage(theImage);
			else if ((*theImage)->gworld && 
						EqualSizeRect(&(*theImage)->gworld->portRect, &(*theImage)->wrect))
				UpdateImage(theImage);
		}
	}
}

//=====================================================================================
// void UpdateNextSlowImage(void)
//=====================================================================================
// Traverses the window list in search of the next window to be updated.
//=====================================================================================

static void UpdateNextSlowImage(void)
{
	WindowPtr theWindow = FWFrontWindow();
	ImageHandle theImage;

	if (theWindow) {
		short var = GetWVariant(theWindow);
		if (var == movableDBoxProc || (var >= dBoxProc && var <= altDBoxProc)) return;
	}
	for ( ; theWindow; theWindow = NextWindow(theWindow)) {
		if ((theImage = FindImage(theWindow)) && !Aborted(theImage) &&
					!EmptyRgn((*theImage)->update)) {
			UpdateImage(theImage);
			gLastEventWhen = TickCount() - (kUpdateDelay >> 1);
			break;
		}
	}
}

//=====================================================================================
// void HandleMouseDownDialog(EventRecord *theEvent)
//=====================================================================================
// Handles mouse down events in dialog windows.
//=====================================================================================

extern void HandleMouseDownDialog(EventRecord *theEvent)
{
	Boolean isCmdKey = (theEvent->modifiers & cmdKey) != 0;
	DialogPtr theDialog, frontDialog = FWFrontWindow();
	short itemHit, thePart, var;
	Boolean modalDialog;
	
	thePart = FindWindow(theEvent->where, &theDialog);
	var = GetWVariant(theDialog);
	modalDialog = (var >= dBoxProc && var <= altDBoxProc) || var == movableDBoxProc;
	switch (thePart) {
		case inMenuBar:
			HandleMenuClick(theEvent);
			break;
		case inSysWindow:
			SystemClick(theEvent, theDialog);
			break;
		case inContent:
			if (theDialog != frontDialog) SendMoveToFront(theDialog);
			else if (FWDialogSelect(theEvent, &theDialog, &itemHit))
				DispatchDialogEvent(theDialog, itemHit);
			break;
		case inDrag:
			if (modalDialog && theDialog != frontDialog && !isCmdKey) SysBeep(30);
			else HandleDragClick(theEvent, theDialog);
			break;
		case inGoAway:
			if (modalDialog && theDialog != frontDialog) SysBeep(30);
			else HandleCloseClick(theEvent, theDialog);
			break;
		case inGrow:
			if (modalDialog && theDialog != frontDialog) SysBeep(30);
			else HandleGrowClick(theEvent, theDialog);
			break;
		case inZoomIn:
		case inZoomOut:
			if (modalDialog && theDialog != frontDialog) SysBeep(30);
			else HandleZoomClick(theEvent, thePart, theDialog);
			break;
	}
	gLastEventWhen = TickCount();
}

//=====================================================================================
// void HandleMouseDownEvent(EventRecord *theEvent)
//=====================================================================================
// Handles mouse down events in non-dialog windows.
//=====================================================================================

extern void HandleMouseDownEvent(EventRecord *theEvent)
{
	WindowPtr theWindow;
	short thePart;

	thePart = FindWindow(theEvent->where, &theWindow);
	if (WindowKind(theWindow) == dialogKind) HandleMouseDownDialog(theEvent);

	// if it's a mouse down during a slide show (but not in a floating window)
	// then toggle the visibility of the slide show controls
	else if (gSlideShow == kRunning && WindowKind(theWindow) != floatingWindowKind &&
				(thePart == inContent || thePart == inGrow)) {
		theWindow = GetSlideControlsWindow();
		if (!theWindow) {
			if (OpenSlideControls() == noErr) ChangeActive(GetSlideControlsWindow());
		} else CloseSlideControls();

	// otherwise, dispatch to the appropriate mouse down handler
	} else {
		switch (thePart) {
			case inMenuBar:
				HandleMenuClick(theEvent);
				break;
			case inSysWindow:
				SystemClick(theEvent, theWindow);
				break;
			case inContent:
				HandleContentClick(theEvent, theWindow);
				break;
			case inDrag:
				HandleDragClick(theEvent, theWindow);
				break;
			case inGoAway:
				HandleCloseClick(theEvent, theWindow);
				break;
			case inGrow:
				HandleGrowClick(theEvent, theWindow);
				break;
			case inZoomIn:
			case inZoomOut:
				HandleZoomClick(theEvent, thePart, theWindow);
				break;
		}
	}
	gLastEventWhen = TickCount();
}

//=====================================================================================
// void HandleMenuClick(EventRecord *theEvent)
//=====================================================================================
// Handles mouse downs in the menu bar.
//=====================================================================================

extern void HandleMenuClick(EventRecord *theEvent)
{
	AdjustMenus();
	HandleMenuChoice(MenuSelect(theEvent->where));
	AdjustMenus();
}

//=====================================================================================
// void HandleContentClick(EventRecord *theEvent, WindowPtr theWindow)
//=====================================================================================
// Handles mouse downs in the content region of a window.
//=====================================================================================

extern void HandleContentClick(EventRecord *theEvent, WindowPtr theWindow)
{
	WindowPtr frontWindow = FWFrontWindow();
	short var = GetWVariant(frontWindow);
	OSType id = GetWRefCon(theWindow);
	ImageHandle theImage;
	
	if ((var == dBoxProc || var == movableDBoxProc) && theWindow != frontWindow)
		SysBeep(30);
	else if (id == kSlideControlsWindowID) {
		if (theWindow != frontWindow) SendMoveToFront(theWindow);
		HandleSlideControlsClick(theEvent->where, theEvent->modifiers, true);
	} else if (theImage = FindImage(theWindow)) 
		HandleImageClick(theImage, theEvent);
	else if (theWindow == GetCommentsWindow()) HandleCommentsClick(theEvent);
	else if (theWindow == GetStatWindow()) HandleStatClick(theEvent);
	else if (theWindow != frontWindow && theWindow != FrontWindow())
		SendMoveToFront(theWindow);
	else if (id == kHelpWindowID) 
		HandleHelpClick(theEvent->where);
}

//=====================================================================================
// void HandleDragClick(EventRecord *theEvent, WindowPtr theWindow)
//=====================================================================================
// Handles mouse downs in the drag region of a window.
//=====================================================================================

extern void HandleDragClick(EventRecord *theEvent, WindowPtr theWindow)
{
	Boolean isCmdKey = (theEvent->modifiers & cmdKey) != 0;
	WindowPtr frontWindow = FWFrontWindow();
	Rect theRect = (*GetGrayRgn())->rgnBBox;
	short var = GetWVariant(frontWindow);

	if ((var == dBoxProc || var == movableDBoxProc) && theWindow != frontWindow && !isCmdKey)
		SysBeep(30);
	else {
		if (theWindow != frontWindow && theWindow != FrontWindow() && !isCmdKey)
			SendMoveToFront(theWindow);
		FWDragWindow(theWindow, theEvent->where, &theRect);
		theRect = theWindow->portRect;
		GlobalRect(&theRect, theWindow);
		SendSetWindowBounds(theWindow, &theRect);
	}
}

//=====================================================================================
// void HandleCloseClick(EventRecord *theEvent, WindowPtr theWindow)
//=====================================================================================
// Handles mouse downs in the close box of a window.
//=====================================================================================

extern void HandleCloseClick(EventRecord *theEvent, WindowPtr theWindow)
{
	WindowPtr nextWindow;
	short firstKind;

	if (TrackGoAway(theWindow, theEvent->where)) {
		if (theEvent->modifiers & optionKey) {
			firstKind = WindowKind(theWindow);
			for (theWindow = GetFirstWindow(); theWindow; theWindow = nextWindow) {
				nextWindow = NextWindow(theWindow);
				if (theWindow == GetSlideControlsWindow()) continue;
				if ((firstKind == floatingWindowKind && WindowKind(theWindow) == floatingWindowKind) ||
							(firstKind != floatingWindowKind && WindowKind(theWindow) != floatingWindowKind))
					SendCloseWindow(theWindow);
			}
		} else SendCloseWindow(theWindow);
	}
}

//=====================================================================================
// void HandleGrowClick(EventRecord *theEvent, WindowPtr theWindow)
//=====================================================================================
// Handles mouse downs in the grow region of a window.
//=====================================================================================

extern void HandleGrowClick(EventRecord *theEvent, WindowPtr theWindow)
{
	WindowPtr frontWindow = FWFrontWindow();
	short var = GetWVariant(frontWindow);
	
	if ((var == dBoxProc || var == movableDBoxProc) && theWindow != frontWindow)
		SysBeep(30);
	else if (GetWRefCon(theWindow) == kSlideControlsWindowID) 
		HandleContentClick(theEvent, theWindow);
	else if (theWindow != frontWindow && theWindow != FrontWindow())
		SendMoveToFront(theWindow);
	else if (GetWRefCon(theWindow) == kHelpWindowID) 
		HandleHelpGrow(theEvent->where);
}

//=====================================================================================
// void HandleZoomClick(EventRecord *theEvent, short thePart, WindowPtr theWindow)
//=====================================================================================
// Handles mouse downs in the zoom box of a window.
//=====================================================================================

extern void HandleZoomClick(EventRecord *theEvent, short thePart, WindowPtr theWindow)
{
	if (TrackBox(theWindow, theEvent->where, thePart)) 
		SendSetZoomed(theWindow, !IsZoomed(theWindow));
}

//=====================================================================================
// void HandleKeyDownDialog(EventRecord *theEvent)
//=====================================================================================
// Handles key down events for a dialog.
//=====================================================================================

extern void HandleKeyDownDialog(EventRecord *theEvent)
{
	Boolean isCmdKey = (theEvent->modifiers & cmdKey) != 0, isCancelKey, isOKKey, isHelpKey;
	uchar theChar = theEvent->message & charCodeMask;
	DialogPtr theDialog = FWFrontWindow();
	OSType dialogID = GetWRefCon(theDialog);
	short itemHit = 0;

	isCancelKey = (theChar == kEscapeChar) || (isCmdKey && theChar == '.');
	isHelpKey = (theChar == kHelpChar) || (isCmdKey && (theChar == '/' || theChar == '?'));
	isOKKey = (theChar == kReturnChar || theChar == kEnterChar);
	
	// if the help key was hit, select the appropriate menu item
	if (isHelpKey) {
		HiliteMenu(kHMHelpMenuID);
		HandleMenuChoice(MakeMenuSelection(kHMHelpMenuID, gHelpItem));

	// handle the cmd-. and escape combinations
	} else if (isCancelKey) itemHit = HandleDialogCancelKey(theDialog);

	// handle return or enter
	else if (isOKKey) itemHit = HandleDialogOKKey(theDialog);

	// handle command-key combinations
	else if (isCmdKey) {
		if (theChar == '=') HandleMenuChoice(MenuKey('+'));
		else HandleMenuChoice(PowerMenuKey(theEvent->message, theEvent->modifiers, GetMHandle(rFileMenu)));

	// handle single-letter buttons
	} else if ((theChar >= 'A' && theChar <= 'Z') || (theChar >= 'a' && theChar <= 'z'))
		itemHit = HandleDialogLetterKey(theDialog, theChar);

	// make a special exception for certain dialogs before further processing
	else if (dialogID == kSlideShowDialogID) {
		if (!HandleSlideOptionsKey(theChar)) FWDialogSelect(theEvent, &theDialog, &itemHit);
	} else if (dialogID == kPrefsDialogID) {
		if (!HandlePrefsKey(theChar)) FWDialogSelect(theEvent, &theDialog, &itemHit);
	
	// otherwise, dispatch to the dialog handler
	} else FWDialogSelect(theEvent, &theDialog, &itemHit);

	// if we were passed back an item to hit, hit it
	if (itemHit) DispatchDialogEvent(theDialog, itemHit);
}

//=====================================================================================
// void HandleKeyDownEvent(EventRecord *theEvent)
//=====================================================================================
// Handles key down events for a non-dialog window.
//=====================================================================================

extern void HandleKeyDownEvent(EventRecord *theEvent)
{
	Boolean isCmdKey = (theEvent->modifiers & cmdKey) != 0, isAbortKey, isHelpKey;
	uchar theChar = theEvent->message & charCodeMask;
	WindowPtr frontWindow = FWFrontWindow();

	// if this should have been a dialog event, treat it as such
	if (WindowKind(frontWindow) == dialogKind) {
		HandleKeyDownDialog(theEvent);
		return;
	}
	AdjustMenus();
	isAbortKey = (theChar == kEscapeChar) || (isCmdKey && theChar == '.');
	isHelpKey = (theChar == kHelpChar) || (isCmdKey && (theChar == '/' || theChar == '?'));
		
	// if we're in a slide show, dispatch to the slide show handler
	if (gSlideShow && !isCmdKey) {
		HandleSlideControlsKey(theChar, theEvent->modifiers, true);
		return;
	}

	// if the help key was hit, select the appropriate menu item
	else if (isHelpKey) {
		HiliteMenu(kHMHelpMenuID);
		HandleMenuChoice(MakeMenuSelection(kHMHelpMenuID, gHelpItem));

	// handle command-key combinations
	} else if (isCmdKey) {
		if (theChar == '=') HandleMenuChoice(MenuKey('+'));
		else HandleMenuChoice(PowerMenuKey(theEvent->message, theEvent->modifiers, GetMHandle(rFileMenu)));

	// everything else goes to the appropriate window
	} else if (frontWindow && GetWRefCon(frontWindow) == kHelpWindowID)
		HandleHelpKey(theChar, (theEvent->message & keyCodeMask) >> 8);

	AdjustMenus();
	gLastEventWhen = TickCount();
}

//=====================================================================================
// void HandleActivateDialog(EventRecord *theEvent)
//=====================================================================================
// Handles activate events for a dialog.
//=====================================================================================

extern void HandleActivateDialog(EventRecord *theEvent)
{
	DialogPtr theDialog = (DialogPtr)theEvent->message;
	short itemHit;
	
	if (GetWRefCon(theDialog) == sfMainDialogRefCon) return;
	FWDialogSelect(theEvent, &theDialog, &itemHit);
}

//=====================================================================================
// void HandleActivateEvent(EventRecord *theEvent)
//=====================================================================================
// Handles activate events for a non-dialog window.
//=====================================================================================

extern void HandleActivateEvent(EventRecord *theEvent)
{
	WindowPtr theWindow = (WindowPtr)theEvent->message;
	Boolean nowActive = (theEvent->modifiers & 1) != 0;
	ImageHandle theImage = FindImage(theWindow);

	if (!theWindow) return;
	PushPort();
	MySetPort((CGrafPtr)theWindow);
	switch (GetWRefCon(theWindow)) {
		case kHelpWindowID:
			HandleHelpActivate(nowActive);
			break;
		default:
			if (theImage) HandleImageActivate(theImage, nowActive);
			break;
	}
	PopPort();
}

//=====================================================================================
// void HandleUpdateDialog(EventRecord *theEvent)
//=====================================================================================
// Handles update events for a dialog.
//=====================================================================================

extern void HandleUpdateDialog(EventRecord *theEvent)
{
	DialogPtr theDialog = (DialogPtr)theEvent->message;
	OSType dialogID = GetWRefCon(theDialog);
	
	if (dialogID == sfMainDialogRefCon) return;
	PushPort();
	MySetPort((CGrafPtr)theDialog);
	BeginUpdate(theDialog);
	UpdateDialog(theDialog, theDialog->visRgn);
	if (dialogID == kSlideShowDialogID) UpdateSlideOptionsButtons();
	EndUpdate(theDialog);
	PopPort();
}

//=====================================================================================
// void HandleUpdateEvent(EventRecord *theEvent)
//=====================================================================================
// Handles update events for a non-dialog window.
//=====================================================================================

extern void HandleUpdateEvent(EventRecord *theEvent)
{
	WindowPtr theWindow = (WindowPtr)theEvent->message;
	ImageHandle theImage = FindImage(theWindow);
	OSType refCon = GetWRefCon(theWindow);
	Boolean defer = true;

	PushPort();
	MySetPort((CGrafPtr)theWindow);
	if (!theImage) {
		BeginUpdate(theWindow);
		if (WindowKind(theWindow) == dialogKind) UpdateDialog(theWindow, theWindow->visRgn);
		else if (refCon == kHelpWindowID) UpdateHelp();
		else if (refCon == kStatWindowID) DrawStatWindow();
		else if (refCon == kCommentsWindowID) UpdateCommentsWindow();
		else if (refCon == kColorsWindowID) DrawColorsWindow();
		else if (refCon == kSlideControlsWindowID) DrawSlideControlsWindow();
		else if (theWindow == GetSlideBackWindow()) DrawSlideBackWindow();
		EndUpdate(theWindow);
	} else {
		Boolean fastGWorld = (*theImage)->gworld && 
					EqualSizeRect(&(*theImage)->gworld->portRect, &(*theImage)->wrect);
		if (fastGWorld || (theWindow == FWFrontWindow() && !gInBackground)) defer = false;
		if (defer) DeferImageUpdate(theImage);
		else {
			WindowPtr ctlWindow = GetSlideControlsWindow();
			short oldSettings[4], i;
			if (ctlWindow) {
				for (i = kReverseButton; i <= kForwardButton; i++) {
					oldSettings[i] = GetSlideControlButton(i);
					SetSlideControlButton(i, disabled);
				}
				DrawSlideControlsWindow();
			}
			UpdateImage(theImage);
			if (!fastGWorld) gLastEventWhen = TickCount();
			if (ctlWindow) {
				for (i = kReverseButton; i <= kForwardButton; i++)
					SetSlideControlButton(i, oldSettings[i]);
				DrawSlideControlsWindow();
			}
		}
	}
	PopPort();
}

//=====================================================================================
// void HandleOSEvent(EventRecord *theEvent)
//=====================================================================================
// Handles operating system events.
//=====================================================================================

extern void HandleOSEvent(EventRecord *theEvent)
{
	WindowPtr frontWindow;
	Boolean resume;
	short var;
	
	switch ((theEvent->message >> 24) & 0xff) {
		case mouseMovedMessage:
			break;
		case suspendResumeMessage:
			resume = (theEvent->message & resumeFlag) != 0;
			if (resume) { // resume
				SetUpDevices();
				gInBackground = false;
				if (gHidden) UnhideWindows();
				FWShowFloatingWindows();
				frontWindow = FWFrontWindow();
				ChangeActive(frontWindow);
				theEvent->what = activateEvt;
				theEvent->message = (long)frontWindow;
				theEvent->modifiers = 1;
				HandleActivateEvent(theEvent);
			} else { // suspend
				frontWindow = FWFrontWindow();
				if (frontWindow) var = GetWVariant(frontWindow);
				if (!frontWindow || var != movableDBoxProc) FWHideFloatingWindows();
				theEvent->what = activateEvt;
				theEvent->message = (long)FWFrontWindow();
				theEvent->modifiers = 0;
				HandleActivateEvent(theEvent);
				ChangeActive(nil);
				ResetDevices();
				if (!gMenuVisible && !gScreenSaver) UnhideMenuBar();
				gInBackground = true;
			}
			break;
	}
}

//=====================================================================================
// void HandleOSEvent(EventRecord *theEvent)
//=====================================================================================
// Handles operating system events.
//=====================================================================================

static void UnhideWindows(void)
{
	WindowPtr backWindow = GetSlideBackWindow(), theWindow;
	ImageHandle theImage, frontImage = FrontImage();
	
	if (frontImage) FWShowWindow((*frontImage)->window);
	for (theImage = gImageRoot; theImage; theImage = (*theImage)->next)
		if ((*theImage)->window) FWShowWindow((*theImage)->window);
	if (backWindow) FWShowWindow(backWindow);
	for (theWindow = GetFirstWindow(); theWindow; theWindow = NextWindow(theWindow))
		if (WindowKind(theWindow) != floatingWindowKind && !FindImage(theWindow) &&
					theWindow != backWindow) SendBehind(theWindow, backWindow);
	gHidden = false;
	gPendingButton = kForwardButton;
}

//=====================================================================================
// void HandleDiskEvent(EventRecord *theEvent)
//=====================================================================================
// Handles disk inserted events.
//=====================================================================================

extern void HandleDiskEvent(EventRecord *theEvent)
{
	if (HiWord(theEvent->message) != noErr) {
		Point thePoint = { -1, -1 };
		DIBadMount(thePoint, theEvent->message);
	}
}

//=====================================================================================
// void DispatchDialogEvent(DialogPtr theDialog, short theItem)
//=====================================================================================
// Dispatches a dialog event to the appropriate handler.
//=====================================================================================

extern void DispatchDialogEvent(DialogPtr theDialog, short theItem) 
{
	switch (GetWRefCon(theDialog)) {
		case kSlideShowDialogID:
			HandleSlideOptionsEvent(theItem);
			break;
		case kPrefsDialogID:
			HandlePrefsEvent(theItem);
			break;
		case kAboutHelpDialogID:
			HandleAboutHelpEvent(theItem);
			break;
	}
}
