shithub: minivmac

ref: d7ad068d56bdec30805a36a9973f5924ad00641b
dir: /src/OSGLUMAC.c/

View raw version
/*
	OSGLUMAC.c

	Copyright (C) 2009 Philip Cummins, Richard F. Bannister,
		Paul C. Pratt

	You can redistribute this file and/or modify it under the terms
	of version 2 of the GNU General Public License as published by
	the Free Software Foundation.  You should have received a copy
	of the license along with this file; see the file COPYING.

	This file is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	license for more details.
*/

/*
	Operating System GLUe for MACintosh

	All operating system dependent code for the
	Macintosh (pre OS X) platform should go here.

	This is also the "reference" implementation. General
	comments about what the platform dependent code
	does should go here, and not be repeated for each
	platform.

	This code is descended from Richard F. Bannister's Macintosh
	port of vMac, by Philip Cummins.

	The main entry point 'main' is at the end of this file.
*/

#include "CNFGRAPI.h"
#include "SYSDEPNS.h"
#include "ENDIANAC.h"

#include "MYOSGLUE.h"

#include "STRCONST.h"

#ifndef NavigationAvail
#define NavigationAvail 1
#endif

#ifndef AppearanceAvail
#define AppearanceAvail 1
#endif

#ifndef NewNamesAvail
#define NewNamesAvail 1
#endif

#ifndef CALL_NOT_IN_CARBON
#define CALL_NOT_IN_CARBON 1
#endif /* !defined(CALL_NOT_IN_CARBON) */


/* --- information about the environment --- */

/*
	code to determine characteristics
	of the current run time environment.
*/

#define TestBit(i, p) (((uimr)(i) & ((uimr)1 << (p))) != 0)

#ifndef HaveCPUfamM68K
#define HaveCPUfamM68K 0
#endif

#if HaveCPUfamM68K

/* MACENVRN.i */

#ifndef Support64kROM
#define Support64kROM 1
#endif

#define Have64kROM() (LMGetROM85() < 0)

/* -- basic environment checking -- */

#ifndef DebugTrapAvailableChecks
#define DebugTrapAvailableChecks 0
#endif

LOCALFUNC blnr LowToolTrapAvailable(short trap_num)
{
#if DebugTrapAvailableChecks
	if ((trap_num & 0x0800) == 0) {
		DebugStr("\pOSTrap in LowToolTrapAvailable");
		return falseblnr;
	}
	if ((trap_num & 0x07ff) >= 0x200) {
		DebugStr("\pHiToolTrap in LowToolTrapAvailable");
		return falseblnr;
	}
#endif
	return GetToolTrapAddress(trap_num) !=
		GetToolTrapAddress(_Unimplemented);
}

LOCALFUNC blnr HiToolTrapAvailable(short trap_num)
{
#if DebugTrapAvailableChecks
	if ((trap_num & 0x0800) == 0) {
		DebugStr("\pOSTrap in HiToolTrapAvailable");
		return falseblnr;
	}
	if (((trap_num & 0x07ff) < 0x200)
		|| ((trap_num & 0x07ff) >= 0x400))
	{
		DebugStr("\pLowToolTrap in HiToolTrapAvailable");
		return falseblnr;
	}
#endif
	if (GetToolTrapAddress(_InitGraf)
		== GetToolTrapAddress(0xAA6E))
	{
		return falseblnr;
	} else {
		return GetToolTrapAddress(trap_num) !=
			GetToolTrapAddress(_Unimplemented);
	}
}

LOCALFUNC blnr OSTrapAvailable(short trap_num)
{
#if DebugTrapAvailableChecks
	if ((trap_num & 0x0800) != 0) {
		DebugStr("\pToolTrap in ToolTrapAvailable");
		return falseblnr;
	}
#endif
	return GetOSTrapAddress(trap_num) !=
		GetToolTrapAddress(_Unimplemented);
}

LOCALVAR blnr MyEnvrAttrWaitNextEventAvail;
LOCALVAR blnr HaveEnvrAttrWaitNextEventAvail = falseblnr;

LOCALFUNC blnr HaveWaitNextEventAvail(void)
{
	if (! HaveEnvrAttrWaitNextEventAvail) {
		MyEnvrAttrWaitNextEventAvail =
			LowToolTrapAvailable(_WaitNextEvent);
		HaveEnvrAttrWaitNextEventAvail = trueblnr;
	}
	return MyEnvrAttrWaitNextEventAvail;
}

LOCALVAR blnr MyEnvrAttrGestaltAvail;
LOCALVAR blnr HaveEnvrAttrGestaltAvail = falseblnr;

LOCALFUNC blnr HaveGestaltAvail(void)
{
	if (! HaveEnvrAttrGestaltAvail) {
		MyEnvrAttrGestaltAvail =
			(! Have64kROM()) &&
			OSTrapAvailable(_Gestalt);
			/*
				contrary to all the documentation,
				TrapAvailable check by itself doesn't
				work on 64k ROM, because a tool box trap
				has the same trap number, and both
				GetOSTrapAddress and GetToolTrapAddress
				are the same as GetTrapAddress on a 64k ROM.
			*/
		HaveEnvrAttrGestaltAvail = trueblnr;
	}
	return MyEnvrAttrGestaltAvail;
}

#else

/* for PowerPC, assume always have these routines */

#define HaveWaitNextEventAvail() trueblnr
#define HaveGestaltAvail() trueblnr

#endif

LOCALVAR blnr MyEnvrAttrAliasMgrAvail;
LOCALVAR blnr HaveEnvrAttrAliasMgrAvail = falseblnr;

LOCALFUNC blnr HaveAliasMgrAvail(void)
{
	if (! HaveEnvrAttrAliasMgrAvail) {
		long reply;

		MyEnvrAttrAliasMgrAvail =
			HaveGestaltAvail()
			&& (noErr == Gestalt(gestaltAliasMgrAttr, &reply))
			&& TestBit(reply, gestaltAliasMgrPresent);
		HaveEnvrAttrAliasMgrAvail = trueblnr;
	}
	return MyEnvrAttrAliasMgrAvail;
}

LOCALVAR blnr MyEnvrAttrAppleEvtMgrAvail;
LOCALVAR blnr HaveEnvrAttrAppleEvtMgrAvail = falseblnr;

LOCALFUNC blnr HaveAppleEvtMgrAvail(void)
{
	if (! HaveEnvrAttrAppleEvtMgrAvail) {
		long reply;

		MyEnvrAttrAppleEvtMgrAvail =
			HaveGestaltAvail()
			&& (noErr == Gestalt(gestaltAppleEventsAttr, &reply))
			&& TestBit(reply, gestaltAppleEventsPresent);
		HaveEnvrAttrAppleEvtMgrAvail = trueblnr;
	}
	return MyEnvrAttrAppleEvtMgrAvail;
}

#if EnableDragDrop

LOCALVAR blnr MyEnvrAttrDragMgrAvail;
LOCALVAR blnr HaveEnvrAttrDragMgrAvail = falseblnr;

LOCALFUNC blnr HaveDragMgrAvail(void)
{
	if (! HaveEnvrAttrDragMgrAvail) {
		long reply;

		MyEnvrAttrDragMgrAvail =
			HaveGestaltAvail()
			&& (noErr == Gestalt(gestaltDragMgrAttr, &reply))
			&& TestBit(reply, gestaltDragMgrPresent);
		HaveEnvrAttrDragMgrAvail = trueblnr;
	}
	return MyEnvrAttrDragMgrAvail;
}

#endif

#ifndef Windows85APIAvail
#define Windows85APIAvail 1
#endif

#if Windows85APIAvail
LOCALVAR blnr MyEnvrAttrHideShowMenuAvail;
LOCALVAR blnr HaveEnvrAttrHideShowMenuAvail = falseblnr;

LOCALFUNC blnr HaveHideShowMenuAvail(void)
{
	if (! HaveEnvrAttrHideShowMenuAvail) {
		long reply;

		MyEnvrAttrHideShowMenuAvail =
			HaveGestaltAvail()
			&& (noErr == Gestalt(gestaltMenuMgrAttr, &reply));
		HaveEnvrAttrHideShowMenuAvail = trueblnr;
	}
	return MyEnvrAttrHideShowMenuAvail;
}
#endif

#if AppearanceAvail
LOCALVAR blnr MyEnvrAttrAppearanceAvail;
LOCALVAR blnr HaveEnvrAttrAppearanceAvail = falseblnr;

LOCALFUNC blnr HaveAppearanceAvail(void)
{
	if (! HaveEnvrAttrAppearanceAvail) {
		long reply;

		MyEnvrAttrAppearanceAvail =
			HaveGestaltAvail()
			&& (noErr == Gestalt(gestaltAppearanceAttr, &reply));
		HaveEnvrAttrAppearanceAvail = trueblnr;
	}
	return MyEnvrAttrAppearanceAvail;
}
#endif

#if HaveCPUfamM68K
LOCALVAR blnr MyEnvrAttrSndMngrAvail;
LOCALVAR blnr HaveEnvrAttrSndMngrAvail = falseblnr;

LOCALFUNC blnr HaveSndMngrAvail(void)
{
	if (! HaveEnvrAttrSndMngrAvail) {
		MyEnvrAttrSndMngrAvail = LowToolTrapAvailable(_SndNewChannel);
		HaveEnvrAttrSndMngrAvail = trueblnr;
	}
	return MyEnvrAttrSndMngrAvail;
}
#endif

#if NavigationAvail
LOCALVAR blnr MyEnvrAttrNavServicesAvail;
LOCALVAR blnr HaveEnvrAttrNavServicesAvail = falseblnr;

LOCALFUNC blnr HaveNavServicesAvail(void)
{
	if (! HaveEnvrAttrNavServicesAvail) {
		MyEnvrAttrNavServicesAvail = NavServicesAvailable();
		HaveEnvrAttrNavServicesAvail = trueblnr;
	}
	return MyEnvrAttrNavServicesAvail;
}
#endif

#if HaveCPUfamM68K
LOCALVAR blnr MyEnvrAttrFSSpecCallsAvail;
LOCALVAR blnr HaveEnvrAttrFSSpecCallsAvail = falseblnr;

LOCALFUNC blnr HaveFSSpecCallsAvail(void)
{
	if (! HaveEnvrAttrFSSpecCallsAvail) {
		long reply;

		MyEnvrAttrFSSpecCallsAvail =
			HaveGestaltAvail()
			&& (noErr == Gestalt(gestaltFSAttr, &reply))
			&& TestBit(reply, gestaltHasFSSpecCalls);
		HaveEnvrAttrFSSpecCallsAvail = trueblnr;
	}
	return MyEnvrAttrFSSpecCallsAvail;
}
#endif

#if Windows85APIAvail
LOCALVAR blnr MyEnvrAttrNewWndMgrAvail;
LOCALVAR blnr HaveEnvrAttrNewWndMgrAvail = falseblnr;

LOCALFUNC blnr HaveNewWndMgrAvail(void)
{
	if (! HaveEnvrAttrNewWndMgrAvail) {
		long reply;

		MyEnvrAttrNewWndMgrAvail =
			HaveGestaltAvail()
			&& (noErr == Gestalt(gestaltWindowMgrAttr, &reply))
			&& TestBit(reply, gestaltWindowMgrPresentBit);
		HaveEnvrAttrNewWndMgrAvail = trueblnr;
	}
	return MyEnvrAttrNewWndMgrAvail;
}
#endif

/* --- initial initialization --- */

#if defined(__SC__) || ((defined(powerc) || defined(__powerc)) \
	&& ! defined(__MWERKS__))

/* GLOBALVAR */ QDGlobals qd;
#endif

LOCALFUNC blnr InitMacManagers(void)
{
	MaxApplZone();

	{
		int i;

		for (i = 7; --i >= 0; ) {
			MoreMasters();
		}
	}

	InitGraf(&qd.thePort);
	InitFonts();
	InitWindows();
	InitMenus();
	TEInit();
	InitDialogs(NULL);
	InitCursor();
	return trueblnr;
}


/* --- mac style errors --- */

#define CheckSavetMacErr(result) (mnvm_noErr == (err = (result)))
	/*
		where 'err' is a variable of type tMacErr in the function
		this is used in
	*/

#define To_tMacErr(result) ((tMacErr)(ui4b)(result))

#define CheckSaveMacErr(result) (CheckSavetMacErr(To_tMacErr(result)))


/*
	define NotAfileRef to some value that is different
	from any valid open file reference.
*/
#define NotAfileRef (-1)

struct MyDir_R {
	long DirId;
	short VRefNum;
};
typedef struct MyDir_R MyDir_R;

LOCALFUNC tMacErr OpenNamedFileInFolder(MyDir_R *d,
	ps3p fileName, short *refnum)
{
	tMacErr err;

#if HaveCPUfamM68K
	if (! HaveFSSpecCallsAvail()) {
		err = To_tMacErr(FSOpen(fileName, d->VRefNum, refnum));
	} else
#endif
	{
		Boolean isFolder;
		Boolean isAlias;
		FSSpec spec;

		if (CheckSaveMacErr(
			FSMakeFSSpec(d->VRefNum, d->DirId, fileName, &spec)))
		if (CheckSaveMacErr(
			ResolveAliasFile(&spec, trueblnr, &isFolder, &isAlias)))
		if (CheckSaveMacErr(
			FSpOpenDF(&spec, fsRdPerm, refnum)))
		{
		}
	}

	return err;
}

/* --- sending debugging info to file --- */

#if dbglog_HAVE

#define Support64kROM 0
#define tMyErr tMacErr

typedef unsigned char * MyPtr;

LOCALFUNC tMyErr MyHGetDir_v2(MyDir_R *d)
{
	tMyErr err;
	WDPBRec r;

	r.ioCompletion = NULL;
	r.ioNamePtr = NULL;

#if Support64kROM
	if (Have64kROM()) {
		err = PBGetVolSync((ParamBlockRec *)&r);
		d->VRefNum = r.ioVRefNum;
		d->DirId = 0;
	} else
#endif
	{
		err = PBHGetVolSync(&r);
		d->VRefNum = r.ioWDVRefNum;
		d->DirId = r.ioWDDirID;
	}

	return err;
}

LOCALFUNC tMyErr MyWriteBytes_v2(short refNum, MyPtr p, uimr L)
{
	ParamBlockRec r;

	r.ioParam.ioCompletion = NULL;
	r.ioParam.ioRefNum = refNum;
	r.ioParam.ioBuffer = (Ptr)p;
	r.ioParam.ioReqCount = L;
	r.ioParam.ioPosMode = (short) fsFromMark;
	r.ioParam.ioPosOffset = 0;

	return PBWriteSync(&r);
}

LOCALFUNC tMyErr MyCloseFile_v2(short refNum)
{
	ParamBlockRec r;

	r.ioParam.ioCompletion = NULL;
	r.ioParam.ioRefNum = refNum;

	return PBCloseSync(&r);
#if 0
	return (tMyErr)FSClose(refNum);
#endif
}

#define NotAfileRef (-1)

/*
	Probably should use PBHOpenDF instead
	of PBHOpen when it is available.
	(System 7 according to Technical Note FL515)
*/

LOCALFUNC tMyErr MyFileOpen_v2(MyDir_R *d, StringPtr s,
	char Permssn, short *refnum)
{
	tMyErr err;
	HParamBlockRec r;

	r.ioParam.ioCompletion = NULL;
	r.ioParam.ioNamePtr = s;
	r.ioParam.ioVRefNum = d->VRefNum;
	r.ioParam.ioPermssn = Permssn;
	r.ioParam.ioMisc = 0; /* use volume buffer */
	r.ioParam.ioVersNum = 0; /* needed if MFS volume */

#if Support64kROM
	if (Have64kROM()) {
		err = PBOpenSync((ParamBlockRec *)&r);
	} else
#endif
	{
		r.fileParam.ioDirID = d->DirId;
		err = PBHOpenSync(&r);
	}

	if (noErr == err) {
		*refnum = r.ioParam.ioRefNum;
		/*
			Don't change *refnum unless file opened,
			so can initialize to NotAfileRef, and
			compare later before closing in uninit.
		*/
	}
	return err;
}

LOCALFUNC tMyErr MyFileOpenWrite_v2(MyDir_R *d, StringPtr s,
	short *refnum)
{
	return MyFileOpen_v2(d, s, (char)fsWrPerm, refnum);
}

LOCALFUNC tMyErr MyDeleteFile_v2(MyDir_R *d, StringPtr s)
{
	tMyErr err;
	HParamBlockRec r;

	r.fileParam.ioCompletion = NULL;
	r.fileParam.ioVRefNum = d->VRefNum;
	r.fileParam.ioNamePtr = s;
	r.fileParam.ioFVersNum = 0; /* needed if MFS volume */

#if Support64kROM
	if (Have64kROM()) {
		err = PBDeleteSync((ParamBlockRec *)&r);
	} else
#endif
	{
		r.fileParam.ioDirID = d->DirId;
		err = PBHDeleteSync(&r);
	}

	return err;
}

LOCALFUNC tMyErr MyCreateFile_v2(MyDir_R *d, StringPtr s)
{
	tMyErr err;
	HParamBlockRec r;

	r.fileParam.ioFlVersNum = 0;
		/*
			Think reference says to do this,
			but not Inside Mac IV
		*/

	r.fileParam.ioCompletion = NULL;
	r.fileParam.ioNamePtr = s;
	r.fileParam.ioVRefNum = d->VRefNum;
	r.fileParam.ioFVersNum = 0; /* needed if MFS volume */

#if Support64kROM
	if (Have64kROM()) {
		err = PBCreateSync((ParamBlockRec *)&r);
	} else
#endif
	{
		r.fileParam.ioDirID = d->DirId;
		err = PBHCreateSync(&r);
	}

	return err;
}

LOCALFUNC tMyErr MyFileGetInfo_v2(MyDir_R *d, StringPtr s,
	HParamBlockRec *r)
{
	tMyErr err;

	r->fileParam.ioCompletion = NULL;
	r->fileParam.ioNamePtr = s;
	r->fileParam.ioVRefNum = d->VRefNum;
	r->fileParam.ioFVersNum = (char)0; /* needed if MFS volume */
	r->fileParam.ioFDirIndex = (short)0;

#if Support64kROM
	if (Have64kROM()) {
		err = PBGetFInfoSync((ParamBlockRec *)r);
	} else
#endif
	{
		r->fileParam.ioDirID = d->DirId;
		err = PBHGetFInfoSync(r);
	}

	return err;
}

LOCALFUNC tMyErr MyFileSetInfo_v2(MyDir_R *d, StringPtr s,
	HParamBlockRec *r)
{
	tMyErr err;

	r->fileParam.ioCompletion = NULL;
	r->fileParam.ioNamePtr = s;
	r->fileParam.ioVRefNum = d->VRefNum;
	r->fileParam.ioFVersNum = (char)0; /* needed if MFS volume */

#if Support64kROM
	if (Have64kROM()) {
		err = PBSetFInfoSync((ParamBlockRec *)r);
	} else
#endif
	{
		r->fileParam.ioDirID = d->DirId;
		err = PBHSetFInfoSync(r);
	}

	return err;
}

LOCALFUNC tMyErr MyFileSetTypeCreator_v2(MyDir_R *d, StringPtr s,
	OSType creator, OSType fileType)
{
	tMyErr err;
	HParamBlockRec r;

	if (noErr == (err = MyFileGetInfo_v2(d, s, &r))) {
		r.fileParam.ioFlFndrInfo.fdType = fileType;
		r.fileParam.ioFlFndrInfo.fdCreator = creator;
		err = MyFileSetInfo_v2(d, s, &r);
	}

	return err;
}

LOCALFUNC tMyErr MyCreateFileOverWrite_v2(MyDir_R *d, StringPtr s)
{
	tMyErr err;

	err = MyCreateFile_v2(d, s);
	if (dupFNErr == err) {
		if (noErr == (err = MyDeleteFile_v2(d, s))) {
			err = MyCreateFile_v2(d, s);
		}
	}

	return err;
}

LOCALFUNC tMyErr MyOpenNewFile_v3(MyDir_R *d, StringPtr s,
	OSType creator, OSType fileType,
	short *refnum)
/*
	Deletes old file if already exists.
*/
{
	tMyErr err;

	err = MyCreateFileOverWrite_v2(d, s);
	if (noErr == err) {
		err = MyFileSetTypeCreator_v2(d, s,
			creator, fileType);
		if (noErr == err) {
			err = MyFileOpenWrite_v2(d, s, refnum);
		}

		if (noErr != err) {
			(void) MyDeleteFile_v2(d, s);
				/* ignore any error, since already got one */
		}
	}

	return err;
}


LOCALVAR short dbglog_File = NotAfileRef;
LOCALVAR tMyErr dbglog_err = noErr;

LOCALFUNC blnr dbglog_open0(void)
{
	tMacErr err;
	MyDir_R d;

	if (noErr == (err = MyHGetDir_v2(&d))) {
		err = MyFileOpen_v2(&d, (StringPtr)"\pdbglog",
				(char)fsWrPerm, &dbglog_File);
		if (mnvm_noErr /* fnfErr */ == err) {
			err = SetEOF(dbglog_File, 0);
		} else {
			err = MyOpenNewFile_v3(&d, (StringPtr)"\pdbglog",
				'MPS ', 'TEXT', &dbglog_File);
			err = mnvm_noErr;
		}

	}

	return (mnvm_noErr == err);
}

LOCALPROC dbglog_write0(char *s, uimr L)
{
	if (NotAfileRef != dbglog_File)
	if (noErr == dbglog_err)
	{
		dbglog_err = MyWriteBytes_v2(dbglog_File, (MyPtr)s, L);
	}
}

LOCALPROC dbglog_close0(void)
{
	if (NotAfileRef != dbglog_File) {
		(void)  MyCloseFile_v2(dbglog_File);
		dbglog_File = NotAfileRef;
	}
}

#endif /* dbglog_HAVE */


/* --- control mode and internationalization --- */

#define NeedCell2MacAsciiMap 1

#define WantColorTransValid 1

#include "INTLCHAR.h"

#include "COMOSGLU.h"

#define WantKeyboard_RemapMac 1

#include "CONTROLM.h"

/* --- some simple utilities --- */

GLOBALOSGLUPROC MyMoveBytes(anyp srcPtr, anyp destPtr, si5b byteCount)
{
	BlockMove((Ptr)srcPtr, (Ptr)destPtr, byteCount);
}

/* don't want to include c libraries, so: */
LOCALFUNC si5b CStrLen(char *src)
{
	char *p = src;
	while (*p++ != 0) {
	}
	return ((si5b)p) - ((si5b)src) - 1;
}

#define PStrMaxLength 255

LOCALPROC PStrFromCStr(ps3p r, /* CONST */ char *s)
{
	unsigned short L;

	L = CStrLen(s);
	if (L > PStrMaxLength) {
		L = PStrMaxLength;
	}
	*r++ = L;
	MyMoveBytes((anyp)s, (anyp)r, L);
}

LOCALPROC PStrFromChar(ps3p r, char x)
{
	r[0] = 1;
	r[1] = (char)x;
}

LOCALPROC PStrFromHandle(ps3p r, Handle h, ui5b MaxL)
{
	ui5b L = GetHandleSize(h);

	if (L > MaxL) {
		L = MaxL;
	}

	*r++ = L;
	BlockMove(*h, (Ptr)r, L);
}

LOCALFUNC tMacErr PStrToHand(ps3p s, Handle *r)
{
	return To_tMacErr(PtrToHand((Ptr)(s + 1), r, s[0]));
}

/* --- utilities for adapting to the environment --- */

#ifndef MightNotHaveAppearanceMgrAvail
#define MightNotHaveAppearanceMgrAvail 1
#endif

#ifndef MightNotHaveWindows85Avail
#define MightNotHaveWindows85Avail MightNotHaveAppearanceMgrAvail
#endif

#ifndef LowMemAPIAvail
#define LowMemAPIAvail 1
#endif

#ifndef My_LMGetTime
#if LowMemAPIAvail
#define My_LMGetTime LMGetTime
#else
#define My_LMGetTime() (*(SInt32 *)(0x020C))
#endif
#endif

#ifndef My_LMGetMBarHeight
#if LowMemAPIAvail
#define My_LMGetMBarHeight LMGetMBarHeight
#else
#define My_LMGetMBarHeight() (*(short *)(0x0BAA))
#endif
#endif

#ifndef My_GetGrayRgn
#if /* LowMemAPIAvail */ 0
#define My_GetGrayRgn LMGetGrayRgn
#else
#define My_GetGrayRgn() (*(RgnHandle *)(0x9EE))
#endif
#endif

#ifndef My_LMGetCurApName
#if LowMemAPIAvail
#define My_LMGetCurApName LMGetCurApName
#else
#define My_LMGetCurApName() ((StringPtr) 0x0910)
#endif
#endif

#define MyGetScreenBitsBounds(r) (*r) = qd.screenBits.bounds

#define My_GetRegionBounds(region, bounds) *(bounds) = \
	(**(region)).rgnBBox

#define My_GetPortPixMap(p) ((p)->portPixMap)

#ifndef My_WindowRef
#if NewNamesAvail
#define My_WindowRef WindowRef
#else
#define My_WindowRef WindowPtr
#endif
#endif

#define My_SetPortWindowPort(w) SetPort(w)

LOCALPROC My_InvalWindowRect(My_WindowRef mw, Rect *r)
{
	GrafPtr SavePort;

	GetPort(&SavePort);
	My_SetPortWindowPort(mw);
	InvalRect(r);
	SetPort(SavePort);
}

#define My_GetWindowPortBounds(w, r) *(r) = ((w)->portRect)

LOCALPROC InvalWholeWindow(My_WindowRef mw)
{
	Rect bounds;

	My_GetWindowPortBounds(mw, &bounds);
	My_InvalWindowRect(mw, &bounds);
}

LOCALPROC MySetMacWindContRect(My_WindowRef mw, Rect *r)
{
#if Windows85APIAvail
	if (HaveNewWndMgrAvail()) {
		(void) SetWindowBounds (mw, kWindowContentRgn, r);
	} else
#endif
	{
#if MightNotHaveWindows85Avail
		MoveWindow(mw, r->left, r->top, falseblnr);
		SizeWindow(mw, r->right - r->left, r->bottom - r->top,
			trueblnr);
#endif
	}
	InvalWholeWindow(mw);
}

LOCALFUNC blnr MyGetWindowTitleBounds(My_WindowRef mw, Rect *r)
{
#if Windows85APIAvail
	if (HaveNewWndMgrAvail()) {
		return (noErr == GetWindowBounds(mw,
				kWindowTitleBarRgn, r));
	} else
#endif
	{
#if MightNotHaveWindows85Avail
		My_GetRegionBounds(((WindowPeek)mw)->strucRgn, r);
		r->bottom = r->top + 15;
		r->left += 4;
		r->right -= 4;
#endif
		return trueblnr;
	}
}

#define topLeft(r) (((Point *) &(r))[0])
#define botRight(r) (((Point *) &(r))[1])

LOCALFUNC blnr MyGetWindowContBounds(My_WindowRef mw, Rect *r)
{
#if Windows85APIAvail
	if (HaveNewWndMgrAvail()) {
		return (noErr == GetWindowBounds(mw,
				kWindowContentRgn, r));
	} else
#endif
	{
#if MightNotHaveWindows85Avail
		GrafPtr oldPort;
		GetPort(&oldPort);
		My_SetPortWindowPort(mw);
		My_GetWindowPortBounds(mw, r);
		LocalToGlobal(&topLeft(*r));
		LocalToGlobal(&botRight(*r));
		SetPort(oldPort);
#endif
		return trueblnr;
	}
}

LOCALPROC MyGetGrayRgnBounds(Rect *r)
{
	My_GetRegionBounds(My_GetGrayRgn(), (Rect *)r);
}

/* --- main window data --- */

LOCALVAR WindowPtr gMyMainWindow = NULL;

#if MayFullScreen
LOCALVAR short hOffset;
LOCALVAR short vOffset;
#endif

#if MayFullScreen
LOCALVAR blnr GrabMachine = falseblnr;
#endif

#if VarFullScreen
LOCALVAR blnr UseFullScreen = (WantInitFullScreen != 0);
#endif

#if EnableMagnify
LOCALVAR blnr UseMagnify = (WantInitMagnify != 0);
#endif

#if EnableMagnify
LOCALPROC MyScaleRect(Rect *r)
{
	r->left *= MyWindowScale;
	r->right *= MyWindowScale;
	r->top *= MyWindowScale;
	r->bottom *= MyWindowScale;
}
#endif

LOCALPROC SetScrnRectFromCoords(Rect *r,
	si4b top, si4b left, si4b bottom, si4b right)
{
	r->left = left;
	r->right = right;
	r->top = top;
	r->bottom = bottom;

#if VarFullScreen
	if (UseFullScreen)
#endif
#if MayFullScreen
	{
		OffsetRect(r, - ViewHStart, - ViewVStart);
	}
#endif

#if EnableMagnify
	if (UseMagnify) {
		MyScaleRect(r);
	}
#endif

#if VarFullScreen
	if (UseFullScreen)
#endif
#if MayFullScreen
	{
		OffsetRect(r, hOffset, vOffset);
	}
#endif

}

#if EnableMagnify
#define MyScaledHeight (MyWindowScale * vMacScreenHeight)
#define MyScaledWidth (MyWindowScale * vMacScreenWidth)
#endif

#if EnableMagnify
LOCALVAR ui3p ScalingBuff = nullpr;
#endif

#if EnableMagnify

LOCALVAR ui3p ScalingTabl = nullpr;
#define ScalingTablsz (256 * MyWindowScale)

#define ScrnMapr_DoMap UpdateScaledBWCopy
#define ScrnMapr_Src GetCurDrawBuff()
#define ScrnMapr_Dst ScalingBuff
#define ScrnMapr_SrcDepth 0
#define ScrnMapr_DstDepth 0
#define ScrnMapr_Map ScalingTabl
#define ScrnMapr_Scale MyWindowScale

#include "SCRNMAPR.h"

#endif

#if EnableMagnify
LOCALPROC SetUpScalingTabl(void)
{
	ui3b *p4;
	int i;
	int j;
	int k;
	ui3r bitsRemaining;
	ui3b t1;
	ui3b t2;

	p4 = ScalingTabl;
	for (i = 0; i < 256; ++i) {
		bitsRemaining = 8;
		t2 = 0;
		for (j = 8; --j >= 0; ) {
			t1 = (i >> j) & 1;
			for (k = MyWindowScale; --k >= 0; ) {
				t2 = (t2 << 1) | t1;
				if (--bitsRemaining == 0) {
					*p4++ = t2;
					bitsRemaining = 8;
					t2 = 0;
				}
			}
		}
	}
}
#endif

LOCALPROC DefaultDrawScreenBuff(si4b top, si4b left,
	si4b bottom, si4b right)
{
	BitMap src;
	Rect SrcRect;
	Rect DstRect;

	SrcRect.left = left;
	SrcRect.right = right;
	SrcRect.top = top;
	SrcRect.bottom = bottom;

	src.rowBytes = vMacScreenMonoByteWidth;
	SetRect(&src.bounds, 0, 0, vMacScreenWidth, vMacScreenHeight);
#if EnableMagnify
	if (UseMagnify) {

		if (! ColorTransValid) {
			SetUpScalingTabl();
			ColorTransValid = trueblnr;
		}

		UpdateScaledBWCopy(top, left, bottom, right);

		MyScaleRect(&SrcRect);
		MyScaleRect(&src.bounds);

		src.baseAddr = (Ptr)ScalingBuff;
		src.rowBytes *= MyWindowScale;
	} else
#endif
	{
		src.baseAddr = (Ptr)GetCurDrawBuff();
	}
	SetScrnRectFromCoords(&DstRect, top, left, bottom, right);
	CopyBits(&src,
		&gMyMainWindow->portBits,
		&SrcRect, &DstRect, srcCopy, NULL);
	/* FrameRect(&SrcRect); for testing */
}

LOCALPROC Update_Screen(void)
{
	GrafPtr savePort;

	GetPort(&savePort);
	My_SetPortWindowPort(gMyMainWindow);

#if VarFullScreen
	if (UseFullScreen)
#endif
#if MayFullScreen
	{
		PaintRect(&gMyMainWindow->portRect);
	}
#endif

	DefaultDrawScreenBuff(0, 0, vMacScreenHeight, vMacScreenWidth);
	SetPort(savePort);
}

LOCALPROC HaveChangedScreenBuff(si4b top, si4b left,
	si4b bottom, si4b right)
{
#if 0 /* experimental code in progress */
	if (UseFullScreen)
	{
		{
			PixMapHandle pm= (**GetMainDevice()).gdPMap;

			/* LockPixels(pm); */
#if EnableMagnify
			if (! UseMagnify) {
#define PixelT ui5b
				PixelT *p1 = (PixelT *)GetPixBaseAddr(pm);
				int i;
				int j;
				int k;
				ui5b *p0 = (ui5b *)GetCurDrawBuff();
				ui5b SkipBytes = GetPixRowBytes(pm)
					- sizeof(PixelT) * vMacScreenWidth;
				ui5b t0;
				PixelT a[2];

				((Ptr)p1) += (long)GetPixRowBytes(pm) * (top + vOffset);
				p1 += hOffset;
				p0 += (long)top * vMacScreenWidth / 32;

				a[0] = (PixelT) -1;
				a[1] = 0;

#if 1
				for (i = bottom - top; --i >= 0; ) {
					for (j = vMacScreenWidth / 32; --j >= 0; ) {
						t0 = *p0++;

						for (k = 32; --k >= 0; ) {
							PixelT v = a[(t0 >> k) & 1];
							*p1++ = v;
						}
					}
					((Ptr)p1) += SkipBytes;
				}
#endif
			} else {
#define PixelT ui5b
				PixelT *p1 = (PixelT *)GetPixBaseAddr(pm);
				int i;
				int j;
				int k;
				ui5b *p0 = (ui5b *)GetCurDrawBuff();
				PixelT *p2;
				ui5b t0;
				PixelT a[2];

				p1 += vOffset * MyScaledWidth;
				p1 += (long)MyWindowScale * (long)MyScaledWidth * top;
				p0 += (long)top * vMacScreenWidth / 32;

				a[0] = (PixelT) -1;
				a[1] = 0;

#if 1
				for (i = bottom - top; --i >= 0; ) {
					p2 = p1;
					for (j = vMacScreenWidth / 32; --j >= 0; ) {
						t0 = *p0++;

						for (k = 32; --k >= 0; ) {
							PixelT v = a[(t0 >> k) & 1];
								/* ((t0 >> k) & 1) - 1 */
							*p1++ = v;
							*p1++ = v;
						}
					}
					for (j = MyScaledWidth; --j >= 0; ) {
						*p1++ = *p2++;
					}
				}
#endif
			}
#endif
			/* UnlockPixels(pm); */
		}
	} else
#endif
	{
		GrafPtr savePort;

		GetPort(&savePort);
		My_SetPortWindowPort(gMyMainWindow);
		DefaultDrawScreenBuff(top, left, bottom, right);
		SetPort(savePort);
	}
}

LOCALPROC MyDrawChangesAndClear(void)
{
	if (ScreenChangedBottom > ScreenChangedTop) {
		HaveChangedScreenBuff(ScreenChangedTop, ScreenChangedLeft,
			ScreenChangedBottom, ScreenChangedRight);
		ScreenClearChanges();
	}
}

GLOBALOSGLUPROC DoneWithDrawingForTick(void)
{
#if EnableFSMouseMotion
	if (HaveMouseMotion) {
		AutoScrollScreen();
	}
#endif
	MyDrawChangesAndClear();
}

/* --- keyboard --- */

LOCALVAR ui5b LastEmKeys[4];

LOCALPROC ZapEmKeys(void)
{
	LastEmKeys[0] = 0;
	LastEmKeys[1] = 0;
	LastEmKeys[2] = 0;
	LastEmKeys[3] = 0;
}

LOCALPROC CheckKeyBoardState(void)
{
	int i;
	int j;
	ui5b NewKeys[4];

	GetKeys(*(KeyMap *)NewKeys);

	for (j = 0; j < 16; ++j) {
		ui3b k1 = ((ui3b *)NewKeys)[j];
		ui3b k2 = ((ui3b *)LastEmKeys)[j];
		ui3b k3 = k1 ^ k2;

		if (k3 != 0) {
			for (i = 0; i < 8; ++i) {
				if ((k3 & (1 << i)) != 0) {
					Keyboard_UpdateKeyMap2(Keyboard_RemapMac(j * 8 + i),
						(k1 & (1 << i)) != 0);
				}
			}
		}
	}
	for (i = 0; i < 4; ++i) {
		LastEmKeys[i] = NewKeys[i];
	}
}

LOCALVAR WantCmdOptOnReconnect = falseblnr;

#define KeyMap_TestBit(m, key) \
	((((ui3b *)m)[(key) / 8] & (1 << ((key) & 7))) != 0)

LOCALPROC ReconnectKeyCodes3(void)
/* so keys already pressed will be ignored */
{
	int i;
	int j;
	blnr oldv;
	blnr newv;
	ui5b NewKeys[4];

	GetKeys(*(KeyMap *)NewKeys);

	/* except check CapsLock */
	oldv = KeyMap_TestBit(LastEmKeys, MKC_CapsLock);
	newv = KeyMap_TestBit(NewKeys, MKC_CapsLock);
	if (oldv != newv) {
		Keyboard_UpdateKeyMap2(MKC_formac_CapsLock, newv);
	}

	/* and except for command/option on receive drop */
	if (WantCmdOptOnReconnect) {
		WantCmdOptOnReconnect = falseblnr;

		for (i = 0; i < 16; ++i) {
			ui3b v = ((ui3b *)NewKeys)[i];
			for (j = 0; j < 8; ++j) {
				if (0 != ((1 << j) & v)) {
					ui3r k = i * 8 + j;
					if (MKC_CapsLock != k) {
						Keyboard_UpdateKeyMap2(Keyboard_RemapMac(k),
							trueblnr);
					}
				}
			}
		}
	}

	for (i = 0; i < 4; ++i) {
		LastEmKeys[i] = NewKeys[i];
	}
}

/* --- cursor hiding --- */

LOCALVAR blnr HaveCursorHidden = falseblnr;
LOCALVAR blnr WantCursorHidden = falseblnr;

LOCALPROC ForceShowCursor(void)
{
	if (HaveCursorHidden) {
		HaveCursorHidden = falseblnr;
		ShowCursor();
	}
}

LOCALPROC SetCursorArrow(void)
{
	SetCursor(&qd.arrow);
}

/* --- cursor moving --- */

/*
	When "EnableFSMouseMotion" the platform
	specific code can get relative mouse
	motion, instead of absolute coordinates
	on the emulated screen. It should
	set HaveMouseMotion to true when
	it is doing this (normally when in
	full screen mode.)

	This can usually be implemented by
	hiding the platform specific cursor,
	and then keeping it within a box,
	moving the cursor back to the center whenever
	it leaves the box. This requires the
	ability to move the cursor (in MyMoveMouse).
*/

/*
	mouse moving code (non OS X) adapted from
	MoveMouse.c by Dan Sears, which says that
	"Based on code from Jon Wtte, Denis Pelli,
	Apple, and a timely suggestion from Bo Lindbergh."
	Also says 'For documentation of the CDM, see Apple
	Tech Note "HW 01 - ADB (The Untold Story: Space Aliens
	ate my mouse)"'
*/

#ifndef TARGET_CPU_PPC
#error "TARGET_CPU_PPC undefined"
#endif

#if TARGET_CPU_PPC
enum {
	glueUppCursorDeviceMoveToProcInfo =
		kD0DispatchedPascalStackBased |
		DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode) |
		RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) |
		DISPATCHED_STACK_ROUTINE_PARAMETER(1,
			SIZE_CODE(sizeof(CursorDevicePtr))) |
		DISPATCHED_STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(long))) |
		DISPATCHED_STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(long))),
	glueUppCursorDeviceNextDeviceProcInfo =
		kD0DispatchedPascalStackBased |
		DISPATCHED_STACK_ROUTINE_SELECTOR_SIZE(kTwoByteCode) |
		RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) |
		DISPATCHED_STACK_ROUTINE_PARAMETER(1,
			SIZE_CODE(sizeof(CursorDevicePtr *)))
};
#endif

#if TARGET_CPU_PPC
LOCALFUNC OSErr
CallCursorDeviceMoveTo(
	CursorDevicePtr ourDevice,
	long absX,
	long absY)
{
	return CallUniversalProc(
		GetToolboxTrapAddress(_CursorDeviceDispatch),
		glueUppCursorDeviceMoveToProcInfo,
		1, ourDevice, absX, absY);
}
#else
#define CallCursorDeviceMoveTo CursorDeviceMoveTo
#endif

#if TARGET_CPU_PPC
LOCALFUNC OSErr
CallCursorDeviceNextDevice(
	CursorDevicePtr *ourDevice)
{
	return CallUniversalProc(
		GetToolboxTrapAddress(_CursorDeviceDispatch),
		glueUppCursorDeviceNextDeviceProcInfo,
		0xB, ourDevice);
}
#else
#define CallCursorDeviceNextDevice CursorDeviceNextDevice
#endif

#if ! TARGET_CPU_PPC
pascal void CallCursorTask(void) =
{
	0x2078, 0x08EE,  /* MOVE.L jCrsrTask,A0 */
	0x4E90           /* JSR (A0) */
};
#endif

/*
	Low memory globals for the mouse
*/

#define MyRawMouse   0x082C
	/* low memory global that has current mouse loc */
#define MyMTemp      0x0828
	/* low memory global that has current mouse loc */
#define MyCrsrNew    0x08CE
	/* set after you change mtemp and rawmouse */
#define MyCrsrCouple 0x08CF
	/* true if the cursor is tied to the mouse */

LOCALFUNC blnr MyMoveMouse(si4b h, si4b v)
{
	/*
		Move the cursor to the point h, v
		on the emulated screen.
		if detect that this fails return falseblnr,
		otherwise return trueblnr.
		(on some platforms it is possible to
		move the curser, but there is no
		way to detect failure.)
	*/
	GrafPtr oldPort;
	Point CurMousePos;
	Point NewMousePos;
	ui5b difftime;
	blnr IsOk;
	long int StartTime = TickCount();

#if VarFullScreen
	if (UseFullScreen)
#endif
#if MayFullScreen
	{
		h -= ViewHStart;
		v -= ViewVStart;
	}
#endif

#if EnableMagnify
	if (UseMagnify) {
		h *= MyWindowScale;
		v *= MyWindowScale;
	}
#endif

#if VarFullScreen
	if (UseFullScreen)
#endif
#if MayFullScreen
	{
		h += hOffset;
		v += vOffset;
	}
#endif

	CurMousePos.h = h;
	CurMousePos.v = v;

	GetPort(&oldPort);
	My_SetPortWindowPort(gMyMainWindow);
	LocalToGlobal(&CurMousePos);

	do {

#if HaveCPUfamM68K
		if (! HiToolTrapAvailable(_CursorDeviceDispatch)) {
			*(Point *)MyRawMouse = CurMousePos;
			*(Point *)MyMTemp = CurMousePos;
			*(Ptr)MyCrsrNew = *(Ptr)MyCrsrCouple;
#if ! TARGET_CPU_PPC
			CallCursorTask();
#endif
		} else
#endif
		{
			CursorDevice *firstMouse = NULL;
			CallCursorDeviceNextDevice(&firstMouse);
			if (firstMouse != NULL) {
				CallCursorDeviceMoveTo(firstMouse,
					(long) CurMousePos.h,
					(long) CurMousePos.v);
			}
		}

		GetMouse(&NewMousePos);
		IsOk = (h == NewMousePos.h) && (v == NewMousePos.v);
		difftime = (ui5b)(TickCount() - StartTime);
	} while ((! IsOk) && (difftime < 5));

	SetPort(oldPort);
	return IsOk;
}

#if EnableFSMouseMotion
LOCALPROC AdjustMouseMotionGrab(void)
{
	if (gMyMainWindow != NULL) {
#if MayFullScreen
		if (GrabMachine) {
			/*
				if magnification changes, need to reset,
				even if HaveMouseMotion already true
			*/
			if (MyMoveMouse(ViewHStart + (ViewHSize / 2),
				ViewVStart + (ViewVSize / 2)))
			{
				SavedMouseH = ViewHStart + (ViewHSize / 2);
				SavedMouseV = ViewVStart + (ViewVSize / 2);
				HaveMouseMotion = trueblnr;
			}
		} else
#endif
		{
			if (HaveMouseMotion) {
				(void) MyMoveMouse(CurMouseH, CurMouseV);
				HaveMouseMotion = falseblnr;
			}
		}
	}
}
#endif

#if EnableFSMouseMotion
LOCALPROC MyMouseConstrain(void)
{
	si4b shiftdh;
	si4b shiftdv;

	if (SavedMouseH < ViewHStart + (ViewHSize / 4)) {
		shiftdh = ViewHSize / 2;
	} else if (SavedMouseH > ViewHStart + ViewHSize - (ViewHSize / 4)) {
		shiftdh = - ViewHSize / 2;
	} else {
		shiftdh = 0;
	}
	if (SavedMouseV < ViewVStart + (ViewVSize / 4)) {
		shiftdv = ViewVSize / 2;
	} else if (SavedMouseV > ViewVStart + ViewVSize - (ViewVSize / 4)) {
		shiftdv = - ViewVSize / 2;
	} else {
		shiftdv = 0;
	}
	if ((shiftdh != 0) || (shiftdv != 0)) {
		SavedMouseH += shiftdh;
		SavedMouseV += shiftdv;
		if (! MyMoveMouse(SavedMouseH, SavedMouseV)) {
			HaveMouseMotion = falseblnr;
		}
	}
}
#endif

LOCALPROC MousePositionNotify(Point NewMousePos)
{
	blnr ShouldHaveCursorHidden = trueblnr;

#if VarFullScreen
	if (UseFullScreen)
#endif
#if MayFullScreen
	{
		NewMousePos.h -= hOffset;
		NewMousePos.v -= vOffset;
	}
#endif
#if VarFullScreen
	else
#endif
#if MayNotFullScreen
	{
		if (! PtInRgn(NewMousePos, gMyMainWindow->visRgn)) {
			ShouldHaveCursorHidden = falseblnr;
		}
	}
#endif

#if EnableMagnify
	if (UseMagnify) {
		NewMousePos.h /= MyWindowScale;
		NewMousePos.v /= MyWindowScale;
	}
#endif

#if VarFullScreen
	if (UseFullScreen)
#endif
#if MayFullScreen
	{
		NewMousePos.h += ViewHStart;
		NewMousePos.v += ViewVStart;
	}
#endif

#if EnableFSMouseMotion
	if (HaveMouseMotion) {
		MyMousePositionSetDelta(
			NewMousePos.h - SavedMouseH, NewMousePos.v - SavedMouseV);
		SavedMouseH = NewMousePos.h;
		SavedMouseV = NewMousePos.v;
	} else
#endif
	{
		if (NewMousePos.h < 0) {
			NewMousePos.h = 0;
			ShouldHaveCursorHidden = falseblnr;
		} else if (NewMousePos.h >= vMacScreenWidth) {
			NewMousePos.h = vMacScreenWidth - 1;
			ShouldHaveCursorHidden = falseblnr;
		}
		if (NewMousePos.v < 0) {
			NewMousePos.v = 0;
			ShouldHaveCursorHidden = falseblnr;
		} else if (NewMousePos.v >= vMacScreenHeight) {
			NewMousePos.v = vMacScreenHeight - 1;
			ShouldHaveCursorHidden = falseblnr;
		}

#if VarFullScreen
		if (UseFullScreen)
#endif
#if MayFullScreen
		{
			ShouldHaveCursorHidden = trueblnr;
		}
#endif

		/* if (ShouldHaveCursorHidden || CurMouseButton) */
		/*
			for a game like arkanoid, would like mouse to still
			move even when outside window in one direction
		*/
		MyMousePositionSet(NewMousePos.h, NewMousePos.v);
	}

	WantCursorHidden = ShouldHaveCursorHidden;
}

LOCALPROC MousePositionNotifyFromGlobal(Point NewMousePos)
{
	GrafPtr oldPort;

	GetPort(&oldPort);
	My_SetPortWindowPort(gMyMainWindow);
	GlobalToLocal(&NewMousePos);
	SetPort(oldPort);

	MousePositionNotify(NewMousePos);
}

LOCALPROC CheckMouseState(void)
{
	Point NewMousePos;
	GrafPtr oldPort;

	GetPort(&oldPort);
	My_SetPortWindowPort(gMyMainWindow);
	GetMouse(&NewMousePos);
	SetPort(oldPort);

	MousePositionNotify(NewMousePos);
}

LOCALPROC DisconnectKeyCodes3(void)
{
	DisconnectKeyCodes2();

	MyMouseButtonSet(falseblnr);

	ForceShowCursor();
}


/* --- time, date, location --- */

#define dbglog_TimeStuff (0 && dbglog_HAVE)

/*
	be sure to avoid getting confused if TickCount
	overflows and wraps.
*/

LOCALVAR ui5b TrueEmulatedTime = 0;
	/*
		The amount of time the program has
		been running, measured in Macintosh
		"ticks". There are 60.14742 ticks per
		second.

		(time when the emulation is
		stopped for more than a few ticks
		should not be counted.)
	*/

LOCALVAR long int LastTime;

LOCALPROC StartUpTimeAdjust(void)
{
	/*
		prepare to call UpdateTrueEmulatedTime.

		will be called again when haven't been
		regularly calling UpdateTrueEmulatedTime,
		(such as the emulation has been stopped).
	*/
	LastTime = TickCount();
}

LOCALPROC UpdateTrueEmulatedTime(void)
{
	/*
		Update TrueEmulatedTime. usually
		need to convert between how the
		host operating system measures
		time and Macintosh ticks. But
		not for this port.
	*/
	long int LatestTime = TickCount();
	si5b TimeDiff = LatestTime - LastTime;

	if (TimeDiff != 0) {
		LastTime = LatestTime;

		if (TimeDiff >= 0) {
			if (TimeDiff > 16) {
				/* emulation interrupted, forget it */
				++TrueEmulatedTime;

#if dbglog_TimeStuff
				dbglog_writelnNum("emulation interrupted",
					TrueEmulatedTime);
#endif
			} else {
				TrueEmulatedTime += TimeDiff;
			}
		}
	}
}

LOCALFUNC blnr CheckDateTime(void)
{
	/*
		Update CurMacDateInSeconds, the number
		of seconds since midnight January 1, 1904.

		return true if CurMacDateInSeconds is
		different than it was on the last
		call to CheckDateTime.
	*/
	ui5b NewMacDateInSecond;

	NewMacDateInSecond = My_LMGetTime();
	if (CurMacDateInSeconds != NewMacDateInSecond) {
		CurMacDateInSeconds = NewMacDateInSecond;
		return trueblnr;
	} else {
		return falseblnr;
	}
}

LOCALFUNC blnr InitLocationDat(void)
{
#if AutoLocation || AutoTimeZone
	MachineLocation loc;

	ReadLocation(&loc);
#if AutoLocation
	CurMacLatitude = (ui5b)loc.latitude;
	CurMacLongitude = (ui5b)loc.longitude;
#endif
#if AutoTimeZone
	CurMacDelta = (ui5b)loc.u.gmtDelta;
#endif
#endif

	(void) CheckDateTime();

	return trueblnr;
}

/* --- sound --- */

#if MySoundEnabled

#define kLn2SoundBuffers 4 /* kSoundBuffers must be a power of two */
#define kSoundBuffers (1 << kLn2SoundBuffers)
#define kSoundBuffMask (kSoundBuffers - 1)

#define DesiredMinFilledSoundBuffs 3
	/*
		if too big then sound lags behind emulation.
		if too small then sound will have pauses.
	*/

#define kLnOneBuffLen 9
#define kLnAllBuffLen (kLn2SoundBuffers + kLnOneBuffLen)
#define kOneBuffLen (1UL << kLnOneBuffLen)
#define kAllBuffLen (1UL << kLnAllBuffLen)
#define kLnOneBuffSz (kLnOneBuffLen + kLn2SoundSampSz - 3)
#define kLnAllBuffSz (kLnAllBuffLen + kLn2SoundSampSz - 3)
#define kOneBuffSz (1UL << kLnOneBuffSz)
#define kAllBuffSz (1UL << kLnAllBuffSz)
#define kOneBuffMask (kOneBuffLen - 1)
#define kAllBuffMask (kAllBuffLen - 1)
#define dbhBufferSize (kAllBuffSz + kOneBuffSz)

#define dbglog_SoundStuff (0 && dbglog_HAVE)
#define dbglog_SoundBuffStats (0 && dbglog_HAVE)

LOCALVAR tpSoundSamp TheSoundBuffer = nullpr;
volatile static ui4b ThePlayOffset;
volatile static ui4b TheFillOffset;
volatile static ui4b MinFilledSoundBuffs;
#if dbglog_SoundBuffStats
LOCALVAR ui4b MaxFilledSoundBuffs;
#endif
LOCALVAR ui4b TheWriteOffset;

LOCALPROC MySound_Start0(void)
{
	/* Reset variables */
	ThePlayOffset = 0;
	TheFillOffset = 0;
	TheWriteOffset = 0;
	MinFilledSoundBuffs = kSoundBuffers + 1;
#if dbglog_SoundBuffStats
	MaxFilledSoundBuffs = 0;
#endif
}

GLOBALOSGLUFUNC tpSoundSamp MySound_BeginWrite(ui4r n, ui4r *actL)
{
	ui4b ToFillLen = kAllBuffLen - (TheWriteOffset - ThePlayOffset);
	ui4b WriteBuffContig =
		kOneBuffLen - (TheWriteOffset & kOneBuffMask);

	if (WriteBuffContig < n) {
		n = WriteBuffContig;
	}
	if (ToFillLen < n) {
		/* overwrite previous buffer */
#if dbglog_SoundStuff
		dbglog_writeln("sound buffer over flow");
#endif
		TheWriteOffset -= kOneBuffLen;
	}

	*actL = n;
	return TheSoundBuffer + (TheWriteOffset & kAllBuffMask);
}

#if 4 == kLn2SoundSampSz
LOCALPROC ConvertSoundBlockToNative(tpSoundSamp p)
{
	int i;

	for (i = kOneBuffLen; --i >= 0; ) {
		*p++ -= 0x8000;
	}
}
#else
#define ConvertSoundBlockToNative(p)
#endif

LOCALPROC MySound_WroteABlock(void)
{
#if (4 == kLn2SoundSampSz)
	ui4b PrevWriteOffset = TheWriteOffset - kOneBuffLen;
	tpSoundSamp p = TheSoundBuffer + (PrevWriteOffset & kAllBuffMask);
#endif

#if dbglog_SoundStuff
	dbglog_writeln("enter MySound_WroteABlock");
#endif

	ConvertSoundBlockToNative(p);

	TheFillOffset = TheWriteOffset;

#if dbglog_SoundBuffStats
	{
		ui4b ToPlayLen = TheFillOffset
			- ThePlayOffset;
		ui4b ToPlayBuffs = ToPlayLen >> kLnOneBuffLen;

		if (ToPlayBuffs > MaxFilledSoundBuffs) {
			MaxFilledSoundBuffs = ToPlayBuffs;
		}
	}
#endif
}

LOCALFUNC blnr MySound_EndWrite0(ui4r actL)
{
	blnr v;

	TheWriteOffset += actL;

	if (0 != (TheWriteOffset & kOneBuffMask)) {
		v = falseblnr;
	} else {
		/* just finished a block */

		MySound_WroteABlock();

		v = trueblnr;
	}

	return v;
}

LOCALPROC MySound_SecondNotify0(void)
{
	if (MinFilledSoundBuffs <= kSoundBuffers) {
		if (MinFilledSoundBuffs > DesiredMinFilledSoundBuffs) {
#if dbglog_SoundStuff
			dbglog_writeln("MinFilledSoundBuffs too high");
#endif
			++LastTime;
		} else if (MinFilledSoundBuffs < DesiredMinFilledSoundBuffs) {
#if dbglog_SoundStuff
			dbglog_writeln("MinFilledSoundBuffs too low");
#endif
			++TrueEmulatedTime;
		}
#if dbglog_SoundBuffStats
		dbglog_writelnNum("MinFilledSoundBuffs",
			MinFilledSoundBuffs);
		dbglog_writelnNum("MaxFilledSoundBuffs",
			MaxFilledSoundBuffs);
		MaxFilledSoundBuffs = 0;
#endif
		MinFilledSoundBuffs = kSoundBuffers + 1;
	}
}

LOCALPROC RampSound(tpSoundSamp p,
	trSoundSamp BeginVal, trSoundSamp EndVal)
{
	int i;
	ui5r v = (((ui5r)BeginVal) << kLnOneBuffLen) + (kLnOneBuffLen >> 1);

	for (i = kOneBuffLen; --i >= 0; ) {
		*p++ = v >> kLnOneBuffLen;
		v = v + EndVal - BeginVal;
	}
}

#if 4 == kLn2SoundSampSz
#define ConvertSoundSampleFromNative(v) ((v) + 0x8000)
#else
#define ConvertSoundSampleFromNative(v) (v)
#endif

struct MySoundR {
	tpSoundSamp fTheSoundBuffer;
	volatile ui4b (*fPlayOffset);
	volatile ui4b (*fFillOffset);
	volatile ui4b (*fMinFilledSoundBuffs);

	volatile blnr PlayingBuffBlock;
	volatile trSoundSamp lastv;
	volatile blnr wantplaying;
	volatile blnr StartingBlocks;

	CmpSoundHeader /* ExtSoundHeader */ soundHeader;
};
typedef struct MySoundR   MySoundR;


/*
	Some of this code descended from CarbonSndPlayDB, an
	example from Apple, as found being used in vMac for Mac OS.
*/

LOCALPROC InsertSndDoCommand(SndChannelPtr chan, SndCommand * newCmd)
{
	if (-1 == chan->qHead) {
		chan->qHead = chan->qTail;
	}

	if (1 <= chan->qHead) {
		chan->qHead--;
	} else {
		chan->qHead = chan->qTail;
	}

	chan->queue[chan->qHead] = *newCmd;
}

/* call back */ static pascal void
MySound_CallBack(SndChannelPtr theChannel, SndCommand * theCallBackCmd)
{
	MySoundR *datp =
		(MySoundR *)(theCallBackCmd->param2);
	blnr wantplaying0 = datp->wantplaying;
	trSoundSamp v0 = datp->lastv;

#if dbglog_SoundStuff
	dbglog_writeln("Enter MySound_CallBack");
#endif

	if (datp->PlayingBuffBlock) {
		/* finish with last sample */
#if dbglog_SoundStuff
		dbglog_writeln("done with sample");
#endif

		*datp->fPlayOffset += kOneBuffLen;
		datp->PlayingBuffBlock = falseblnr;
	}

	if ((! wantplaying0) && (kCenterSound == v0)) {
#if dbglog_SoundStuff
		dbglog_writeln("terminating");
#endif
	} else {
		SndCommand playCmd;
		tpSoundSamp p;
		trSoundSamp v1 = v0;
		blnr WantRamp = falseblnr;
		ui4b CurPlayOffset = *datp->fPlayOffset;
		ui4b ToPlayLen = *datp->fFillOffset - CurPlayOffset;
		ui4b FilledSoundBuffs = ToPlayLen >> kLnOneBuffLen;

		if (FilledSoundBuffs < *datp->fMinFilledSoundBuffs) {
			*datp->fMinFilledSoundBuffs = FilledSoundBuffs;
		}

		if (! wantplaying0) {
#if dbglog_SoundStuff
			dbglog_writeln("playing end transistion");
#endif
			v1 = kCenterSound;

			WantRamp = trueblnr;
		} else
		if (datp->StartingBlocks) {
#if dbglog_SoundStuff
			dbglog_writeln("playing start block");
#endif

			if ((ToPlayLen >> kLnOneBuffLen) < 12) {
				datp->StartingBlocks = falseblnr;
#if dbglog_SoundStuff
				dbglog_writeln("have enough samples to start");
#endif

				p = datp->fTheSoundBuffer
					+ (CurPlayOffset & kAllBuffMask);
				v1 = ConvertSoundSampleFromNative(*p);
			}

			WantRamp = trueblnr;
		} else
		if (0 == FilledSoundBuffs) {
#if dbglog_SoundStuff
			dbglog_writeln("playing under run");
#endif

			WantRamp = trueblnr;
		} else
		{
			/* play next sample */
			p = datp->fTheSoundBuffer
				+ (CurPlayOffset & kAllBuffMask);
			datp->PlayingBuffBlock = trueblnr;
			v1 =
				ConvertSoundSampleFromNative(*(p + kOneBuffLen - 1));
#if dbglog_SoundStuff
			dbglog_writeln("playing sample");
#endif
		}

		if (WantRamp) {
			p = datp->fTheSoundBuffer + kAllBuffLen;

#if dbglog_SoundStuff
			dbglog_writelnNum("v0", v0);
			dbglog_writelnNum("v1", v1);
#endif

			RampSound(p, v0, v1);
			ConvertSoundBlockToNative(p);
		}

		datp->soundHeader.samplePtr = (Ptr)p;
		datp->soundHeader.numFrames =
			(unsigned long)kOneBuffLen;

		/* Insert our callback command */
		InsertSndDoCommand (theChannel, theCallBackCmd);

#if 0
		{
			int i;
			tpSoundSamp pS =
				(tpSoundSamp)datp->soundHeader.samplePtr;

			for (i = datp->soundHeader.numFrames; --i >= 0; )
			{
				fprintf(stderr, "%d\n", *pS++);
			}
		}
#endif

		/* Play the next buffer */
		playCmd.cmd = bufferCmd;
		playCmd.param1 = 0;
		playCmd.param2 = (long)&(datp->soundHeader);
		InsertSndDoCommand (theChannel, &playCmd);

		datp->lastv = v1;
	}
}

LOCALVAR MySoundR cur_audio;

LOCALVAR SndCallBackUPP gCarbonSndPlayDoubleBufferCallBackUPP = NULL;

LOCALVAR SndChannelPtr sndChannel = NULL; /* our sound channel */

LOCALPROC MySound_Start(void)
{
	if (NULL == sndChannel)
#if HaveCPUfamM68K
	if (HaveSndMngrAvail())
#endif
	{
		SndCommand callBack;
		SndChannelPtr chan = NULL;

		cur_audio.wantplaying = falseblnr;
		cur_audio.StartingBlocks = falseblnr;

		MySound_Start0();

		SndNewChannel(&chan, sampledSynth, initMono, nil);
		if (NULL != chan) {
			sndChannel = chan;

			cur_audio.PlayingBuffBlock = falseblnr;
			cur_audio.lastv = kCenterSound;
			cur_audio.StartingBlocks = trueblnr;
			cur_audio.wantplaying = trueblnr;

			callBack.cmd = callBackCmd;
			callBack.param1 = 0; /* unused */
			callBack.param2 = (long)&cur_audio;

			sndChannel->callBack =
				gCarbonSndPlayDoubleBufferCallBackUPP;

			(void) SndDoCommand (sndChannel, &callBack, true);
		}
	}
}

#define IgnorableEventMask \
	(mUpMask | keyDownMask | keyUpMask | autoKeyMask)

LOCALPROC MySound_Stop(void)
{
#if dbglog_SoundStuff
	dbglog_writeln("enter MySound_Stop");
#endif

	if (NULL != sndChannel) {
		ui4r retry_limit = 50; /* half of a second */
		SCStatus r;

		cur_audio.wantplaying = falseblnr;
#if dbglog_SoundStuff
		dbglog_writeln("cleared wantplaying");
#endif

label_retry:
		r.scChannelBusy = falseblnr; /* what is this for? */
		if (noErr != SndChannelStatus(sndChannel,
			sizeof(SCStatus), &r))
		{
			/* fail */
		} else
		if ((! r.scChannelBusy) && (kCenterSound == cur_audio.lastv)) {
			/* done */

			/*
				observed reporting not busy unexpectedly,
				so also check lastv.
			*/
		} else
		if (0 == --retry_limit) {
#if dbglog_SoundStuff
			dbglog_writeln("retry limit reached");
#endif
			/*
				don't trust SndChannelStatus, make
				sure don't get in infinite loop.
			*/

			/* done */
		} else
		{
			/*
				give time back, particularly important
				if got here on a suspend event.
			*/
			EventRecord theEvent;

#if dbglog_SoundStuff
			dbglog_writeln("busy, so sleep");
#endif

#if HaveCPUfamM68K
			if (! HaveWaitNextEventAvail()) {
				(void) GetNextEvent(IgnorableEventMask, &theEvent);
			} else
#endif
			{
				(void) WaitNextEvent(IgnorableEventMask,
					&theEvent, 1, NULL);
			}
			goto label_retry;
		}

		SndDisposeChannel(sndChannel, true);
		sndChannel = NULL;
	}

#if dbglog_SoundStuff
	dbglog_writeln("leave MySound_Stop");
#endif
}

#define SOUND_SAMPLERATE rate22khz
	/* = 0x56EE8BA3 = (7833600 * 2 / 704) << 16 */

LOCALFUNC blnr MySound_Init(void)
{
#if dbglog_SoundStuff
	dbglog_writeln("enter MySound_Init");
#endif

	cur_audio.fTheSoundBuffer = TheSoundBuffer;

	cur_audio.fPlayOffset = &ThePlayOffset;
	cur_audio.fFillOffset = &TheFillOffset;
	cur_audio.fMinFilledSoundBuffs = &MinFilledSoundBuffs;
	cur_audio.wantplaying = falseblnr;

	/* Init basic per channel information */
	cur_audio.soundHeader.sampleRate = SOUND_SAMPLERATE;
		/* sample rate */
	cur_audio.soundHeader.numChannels = 1; /* one channel */
	cur_audio.soundHeader.loopStart = 0;
	cur_audio.soundHeader.loopEnd = 0;
	cur_audio.soundHeader.encode = cmpSH /* extSH */;
	cur_audio.soundHeader.baseFrequency = kMiddleC;
	cur_audio.soundHeader.numFrames =
		(unsigned long)kOneBuffLen;
	/* cur_audio.soundHeader.AIFFSampleRate = 0; */
		/* unused */
	cur_audio.soundHeader.markerChunk = nil;
	cur_audio.soundHeader.futureUse2 = 0;
	cur_audio.soundHeader.stateVars = nil;
	cur_audio.soundHeader.leftOverSamples = nil;
	cur_audio.soundHeader.compressionID = 0;
		/* no compression */
	cur_audio.soundHeader.packetSize = 0;
		/* no compression */
	cur_audio.soundHeader.snthID = 0;
	cur_audio.soundHeader.sampleSize = (1 << kLn2SoundSampSz);
		/* 8 or 16 bits per sample */
	cur_audio.soundHeader.sampleArea[0] = 0;
#if 3 == kLn2SoundSampSz
	cur_audio.soundHeader.format = kSoundNotCompressed;
#elif 4 == kLn2SoundSampSz
	cur_audio.soundHeader.format = k16BitNativeEndianFormat;
#else
#error "unsupported kLn2SoundSampSz"
#endif
	cur_audio.soundHeader.samplePtr = (Ptr)TheSoundBuffer;

	gCarbonSndPlayDoubleBufferCallBackUPP =
		NewSndCallBackUPP(MySound_CallBack);
	if (gCarbonSndPlayDoubleBufferCallBackUPP != NULL) {

		MySound_Start();
			/*
				This should be taken care of by LeaveSpeedStopped,
				but since takes a while to get going properly,
				start early.
			*/

		return trueblnr;
	}
	return falseblnr;
}

GLOBALOSGLUPROC MySound_EndWrite(ui4r actL)
{
	if (MySound_EndWrite0(actL)) {
	}
}

LOCALPROC MySound_SecondNotify(void)
{
	if (sndChannel != NULL) {
		MySound_SecondNotify0();
	}
}

#endif

#if MayFullScreen
LOCALPROC AdjustMachineGrab(void)
{
#if EnableFSMouseMotion
	AdjustMouseMotionGrab();
#endif
#if 0
	AdjustMainScreenGrab();
#endif
}
#endif

#if MayFullScreen
LOCALPROC UngrabMachine(void)
{
	GrabMachine = falseblnr;
	AdjustMachineGrab();
}
#endif

/* --- basic dialogs --- */

LOCALPROC NativeStrFromCStr(ps3p r, char *s, blnr AddEllipsis)
{
	int i;
	int L;
	ui3b ps[ClStrMaxLength];

	ClStrFromSubstCStr(&L, ps, s);
	if (AddEllipsis) {
		ClStrAppendChar(&L, ps, kCellEllipsis);
	}

	if (L > 255) {
		L = 255;
	}

	for (i = 0; i < L; ++i) {
		r[i + 1] = Cell2MacAsciiMap[ps[i]];
	}

	r[0] = L;
}

#ifndef HogCPU
#define HogCPU 1
#endif

#if HogCPU
LOCALVAR long NoEventsCounter = 0;
#endif

LOCALVAR blnr gBackgroundFlag = falseblnr;
LOCALVAR blnr gTrueBackgroundFlag = falseblnr;
LOCALVAR blnr CurSpeedStopped = trueblnr;

LOCALVAR blnr ADialogIsUp = falseblnr;

LOCALPROC MyBeginDialog(void)
{
	DisconnectKeyCodes3();
	ADialogIsUp = trueblnr;
#if MayFullScreen
	UngrabMachine();
#endif
}

LOCALPROC MyEndDialog(void)
{
#if HogCPU
	NoEventsCounter = 0;
#endif
	ADialogIsUp = falseblnr;
	ReconnectKeyCodes3();
}


#define kMyStandardAlert 128

LOCALPROC CheckSavedMacMsg(void)
{
	/*
		This is currently only used in the
		rare case where there is a message
		still pending as the program quits.
	*/
	Str255 briefMsgp;
	Str255 longMsgp;

	if (nullpr != SavedBriefMsg) {
		NativeStrFromCStr(briefMsgp, SavedBriefMsg, falseblnr);
		NativeStrFromCStr(longMsgp, SavedLongMsg, falseblnr);
#if AppearanceAvail
		if (HaveAppearanceAvail()) {
			AlertStdAlertParamRec param;
			short itemHit;

			param.movable = 0;
			param.filterProc = nil;
			param.defaultText = "\pOK";
			param.cancelText = nil;
			param.otherText = nil;
			param.helpButton = false;
			param.defaultButton = kAlertStdAlertOKButton;
			param.cancelButton = 0;
			param.position = kWindowDefaultPosition;

			StandardAlert(
				(SavedFatalMsg) ? kAlertStopAlert : kAlertCautionAlert,
				briefMsgp, longMsgp, &param, &itemHit);
		} else
#endif
		{
			ParamText(briefMsgp, longMsgp, "\p", "\p");
			if (SavedFatalMsg) {
				while (StopAlert(kMyStandardAlert, NULL) != 1) {
				}
			} else {
				while (CautionAlert(kMyStandardAlert, NULL) != 1) {
				}
			}
			/* Alert (kMyStandardAlert, 0L); */
		}

		SavedBriefMsg = nullpr;
	}
}

/* --- hide/show menubar --- */

#if MayFullScreen
#if MightNotHaveWindows85Avail
LOCALVAR RgnHandle GrayRgnSave = NULL;
LOCALVAR short mBarHeightSave;
#endif
#endif

#if MayFullScreen
LOCALPROC My_HideMenuBar(void)
{
#if Windows85APIAvail
	if (HaveHideShowMenuAvail()) {
		if (IsMenuBarVisible()) {
			HideMenuBar();
		}
	} else
#endif
	{
#if MightNotHaveWindows85Avail
		if (NULL == GrayRgnSave) {
			RgnHandle mBarRgn = NewRgn();
			if (mBarRgn != NULL) {
				GrayRgnSave = NewRgn();
				if (GrayRgnSave != NULL) {
					CopyRgn(My_GetGrayRgn(), GrayRgnSave);
					RectRgn(mBarRgn, &qd.screenBits.bounds);
					DiffRgn(mBarRgn, My_GetGrayRgn(), mBarRgn);
						/*
							menu bar rgn, plus corner areas
							of main screen
						*/
					mBarHeightSave = My_LMGetMBarHeight();
					LMSetMBarHeight(0);
					UnionRgn(My_GetGrayRgn(), mBarRgn, My_GetGrayRgn());
					PaintBehind(LMGetWindowList(), mBarRgn);
					CalcVisBehind(LMGetWindowList(), mBarRgn);
#if 0
					controlStripHidden = false;
					if (noErr == Gestalt(
						gestaltControlStripVersion, &result))
					{
						if (SBIsControlStripVisible()) {
							controlStripHidden = true;
							SBShowHideControlStrip(false);
						}
					}
#endif
				}
				DisposeRgn(mBarRgn);
			}
		}
#endif
	}
}
#endif

#if MayFullScreen
LOCALPROC My_ShowMenuBar(void)
{
#if Windows85APIAvail
	if (HaveHideShowMenuAvail()) {
		if (! IsMenuBarVisible()) {
			ShowMenuBar();
		}
	} else
#endif
	{
#if MightNotHaveWindows85Avail
		if (GrayRgnSave != NULL) {
			LMSetMBarHeight(mBarHeightSave);
			CopyRgn(GrayRgnSave, My_GetGrayRgn());
			/*
				PaintBehind(LMGetWindowList(), GrayRgnSave);
				CalcVisBehind(LMGetWindowList(), GrayRgnSave);
			*/
			DisposeRgn(GrayRgnSave);
			DrawMenuBar();
			GrayRgnSave = NULL;
#if 0
			if (controlStripHidden) {
				controlStripHidden = falseblnr;
				if (noErr ==
					Gestalt(gestaltControlStripVersion, &result))
				{
					SBShowHideControlStrip(true);
				}
			}
#endif
		}
#endif
	}
}
#endif

#if IncludePbufs
LOCALVAR Handle PbufDat[NumPbufs];
#endif

#if IncludePbufs
LOCALFUNC tMacErr PbufNewFromHandle(Handle h, ui5b count, tPbuf *r)
{
	tPbuf i;
	tMacErr err;

	if (! FirstFreePbuf(&i)) {
		DisposeHandle(h);
		err = mnvm_miscErr;
	} else {
		*r = i;
		PbufDat[i] = h;
		PbufNewNotify(i, count);
		err = mnvm_noErr;
	}

	return err;
}
#endif

#if IncludePbufs
GLOBALOSGLUFUNC tMacErr PbufNew(ui5b count, tPbuf *r)
{
	Handle h;
	tMacErr err = mnvm_miscErr;

	h = NewHandleClear(count);
	if (h != NULL) {
		err = PbufNewFromHandle(h, count, r);
	}

	return err;
}
#endif

#if IncludePbufs
GLOBALOSGLUPROC PbufDispose(tPbuf i)
{
	DisposeHandle(PbufDat[i]);
	PbufDisposeNotify(i);
}
#endif

#if IncludePbufs
LOCALPROC UnInitPbufs(void)
{
	tPbuf i;

	for (i = 0; i < NumPbufs; ++i) {
		if (PbufIsAllocated(i)) {
			PbufDispose(i);
		}
	}
}
#endif

#if IncludePbufs
#define PbufHaveLock 1
#endif

#if IncludePbufs
LOCALFUNC ui3p PbufLock(tPbuf i)
{
	ui3p p;

	Handle h = PbufDat[i];

	if (NULL == h) {
		p = nullpr;
	} else {
		HLock(h);
		p = (ui3p)*h;
	}

	return p;
}
#endif

#if IncludePbufs
LOCALPROC PbufUnlock(tPbuf i)
{
	HUnlock(PbufDat[i]);
}
#endif

#if IncludePbufs
GLOBALOSGLUPROC PbufTransfer(ui3p Buffer,
	tPbuf i, ui5r offset, ui5r count, blnr IsWrite)
{
	Handle h = PbufDat[i];

	HLock(h);
	{
		void *p = ((ui3p)*h) + offset;
		if (IsWrite) {
			BlockMove(Buffer, p, count);
		} else {
			BlockMove(p, Buffer, count);
		}
	}
	HUnlock(h);
}
#endif

/* --- clipboard --- */

#if IncludeHostTextClipExchange
GLOBALOSGLUFUNC tMacErr HTCEexport(tPbuf i)
{
	/*
		PBuf i is an array of macintosh
		style characters. (using the
		MacRoman character set.)

		Should export this Buffer to the
		native clipboard, performing character
		set translation, and eof character translation
		as needed. (Not needed for this port.)

		return 0 if it succeeds, nonzero (a
		Macintosh style error code, but -1
		will do) on failure.
	*/
	OSErr err;

	err = ZeroScrap();
	if (noErr == err) {
		ui5b L = PbufSize[i];
		Handle h = PbufDat[i];
		HLock(h);
		err = PutScrap(L, 'TEXT', *h);
		HUnlock(h);
	}

	PbufDispose(i);

	return (tMacErr)err;
}
#endif

#if IncludeHostTextClipExchange
GLOBALOSGLUFUNC tMacErr HTCEimport(tPbuf *r)
{
	/*
		Import the native clipboard as text,
		and convert it to Macintosh format,
		in a Pbuf.

		return 0 if it succeeds, nonzero (a
		Macintosh style error code, but -1
		will do) on failure.
	*/

	long off;
	long v;
	Handle h;
	OSErr err = (OSErr)mnvm_miscErr;

	h = NewHandle(0);
	if (h != NULL) {
		v = GetScrap(h, 'TEXT', &off);
		if (v < 0) {
			err = v;
		} else {
			err = (OSErr)PbufNewFromHandle(h, v, r);
			h = NULL;
		}
		if (NULL != h) {
			DisposeHandle(h);
		}
	}

	return (tMacErr)err;
}
#endif

/* --- drives --- */

LOCALVAR short Drives[NumDrives]; /* open disk image files */
#if (IncludeSonyGetName || IncludeSonyNew) && HaveCPUfamM68K
LOCALVAR Handle DriveNames[NumDrives];
#endif

LOCALPROC InitDrives(void)
{
	/*
		This isn't really needed, Drives[i] and DriveNames[i]
		need not have valid values when not vSonyIsInserted[i].
	*/
	tDrive i;

	for (i = 0; i < NumDrives; ++i) {
		Drives[i] = NotAfileRef;
#if (IncludeSonyGetName || IncludeSonyNew) && HaveCPUfamM68K
		DriveNames[i] = NULL;
#endif
	}
}

GLOBALOSGLUFUNC tMacErr vSonyTransfer(blnr IsWrite, ui3p Buffer,
	tDrive Drive_No, ui5r Sony_Start, ui5r Sony_Count,
	ui5r *Sony_ActCount)
{
	/*
		return 0 if it succeeds, nonzero (a
		Macintosh style error code, but -1
		will do) on failure.
	*/
	tMacErr result;
	ui5r NewSony_Count = Sony_Count;

	result =
		(tMacErr)SetFPos(Drives[Drive_No], fsFromStart, Sony_Start);
	if (mnvm_noErr == result) {
		if (IsWrite) {
			/*
				write Sony_Count bytes from Buffer, to disk image
				number Drive_No, starting at offset Sony_Start.
			*/

			result = (tMacErr)FSWrite(Drives[Drive_No],
				(long *)&NewSony_Count, Buffer);
		} else {
			/*
				read Sony_Count bytes into Buffer, from disk image
				number Drive_No, starting at offset Sony_Start.
			*/

			result = (tMacErr)FSRead(Drives[Drive_No],
				(long *)&NewSony_Count, Buffer);
		}
	}

	if (nullpr != Sony_ActCount) {
		*Sony_ActCount = NewSony_Count;
	}

	return result;
}

GLOBALOSGLUFUNC tMacErr vSonyGetSize(tDrive Drive_No, ui5r *Sony_Count)
{
	/*
		set Sony_Count to the size of disk image number Drive_No.

		return 0 if it succeeds, nonzero (a
		Macintosh style error code, but -1
		will do) on failure.
	*/
	return GetEOF(Drives[Drive_No], (long *)Sony_Count);
}

LOCALFUNC OSErr vSonyEject0(tDrive Drive_No)
{
	/*
		close disk image number Drive_No.

		return 0 if it succeeds, nonzero (a
		Macintosh style error code, but -1
		will do) on failure.
	*/
	short refnum = Drives[Drive_No];
	Drives[Drive_No] = NotAfileRef; /* not really needed */

	DiskEjectedNotify(Drive_No);

#if (IncludeSonyGetName || IncludeSonyNew) && HaveCPUfamM68K
	{
		Handle h = DriveNames[Drive_No];
		if (NULL != h) {
			DisposeHandle(h);
			DriveNames[Drive_No] = NULL; /* not really needed */
		}
	}
#endif

	return FSClose(refnum);
}

GLOBALOSGLUFUNC tMacErr vSonyEject(tDrive Drive_No)
{
	OSErr result;
	short vRefNum;
	blnr DidEject = falseblnr;
	short refnum = Drives[Drive_No];

	result = GetVRefNum(refnum, &vRefNum);
	if (noErr == result) {
		DidEject = trueblnr;
		result = vSonyEject0(Drive_No);
		(void) FlushVol(NULL, vRefNum);
	}

	if (! DidEject) {
		result = vSonyEject0(Drive_No);
	}

	return (tMacErr)result;
}

#if IncludeSonyNew
GLOBALOSGLUFUNC tMacErr vSonyEjectDelete(tDrive Drive_No)
{
	OSErr result;
	Str255 s;
	blnr DidEject = falseblnr;
	short refnum = Drives[Drive_No];

#if HaveCPUfamM68K
	if (! HaveFSSpecCallsAvail()) {
		Handle h = DriveNames[Drive_No];
		if (NULL != h) {
			short vRefNum;
			result = GetVRefNum(refnum, &vRefNum);
			if (noErr == result) {
				PStrFromHandle(s, h, 255);
				result = vSonyEject0(Drive_No);
				DidEject = trueblnr;
				(void) FSDelete(s, vRefNum);
			}
		}
	} else
#endif
	{
		FCBPBRec b;

		b.ioCompletion = NULL;
		b.ioNamePtr = (StringPtr)s;
		b.ioVRefNum = 0;
		b.ioRefNum = refnum;
		b.ioFCBIndx = 0;
		result = PBGetFCBInfoSync(&b);
		if (noErr == result) {
			FSSpec spec;
			result = FSMakeFSSpec(b.ioFCBVRefNum, b.ioFCBParID,
				s, &spec);
			if (noErr == result) {
				result = vSonyEject0(Drive_No);
				DidEject = trueblnr;
				(void) FSpDelete(&spec);
			}
		}
	}

	if (! DidEject) {
		(void) vSonyEject0(Drive_No);
	}

	return (tMacErr)result;
}
#endif

LOCALPROC UnInitDrives(void)
{
	tDrive i;

	for (i = 0; i < NumDrives; ++i) {
		if (vSonyIsInserted(i)) {
			(void) vSonyEject(i);
		}
	}
}

#if IncludeSonyGetName
GLOBALOSGLUFUNC tMacErr vSonyGetName(tDrive Drive_No, tPbuf *r)
{
	FCBPBRec b;
	Str255 s;
	tMacErr err = mnvm_miscErr;

#if HaveCPUfamM68K
	if (! HaveFSSpecCallsAvail()) {
		Handle h = DriveNames[Drive_No];
		if (NULL != h) {
			PStrFromHandle(s, h, 255);
			err = mnvm_noErr;
		}
	} else
#endif
	{
		b.ioCompletion = NULL;
		b.ioNamePtr = (StringPtr)s;
		b.ioVRefNum = 0;
		b.ioRefNum = Drives[Drive_No];
		b.ioFCBIndx = 0;
		err = To_tMacErr(PBGetFCBInfoSync(&b));
	}

	if (mnvm_noErr == err) {
		Handle h;
		err = PStrToHand(s, &h);
		if (noErr == err) {
			err = PbufNewFromHandle(h, s[0], r);
		}
	}

	return err;
}
#endif

LOCALFUNC tMacErr Sony_Insert0(short refnum, blnr locked, ps3p s)
{
	/*
		Given reference to open file, mount it as
		a disk image file. if "locked", then mount
		it as a locked disk.
	*/

	tDrive Drive_No;

#if ! ((IncludeSonyGetName || IncludeSonyNew) && HaveCPUfamM68K)
	UnusedParam(s);
#endif

	if (! FirstFreeDisk(&Drive_No)) {
		(void) FSClose(refnum);
		return mnvm_tmfoErr; /* too many files open */
	} else {
		Drives[Drive_No] = refnum;
		DiskInsertNotify(Drive_No, locked);
#if (IncludeSonyGetName || IncludeSonyNew) && HaveCPUfamM68K
		if (s != NULL) {
			Handle h;

			if (mnvm_noErr != PStrToHand(s, &h)) {
				h = NULL;
			}
			DriveNames[Drive_No] = h;
		}
#endif
		return mnvm_noErr;
	}
}

LOCALPROC ReportStandardOpenDiskError(tMacErr err)
{
	if (mnvm_noErr != err) {
		if (mnvm_tmfoErr == err) {
			MacMsg(kStrTooManyImagesTitle,
				kStrTooManyImagesMessage, falseblnr);
		} else if (mnvm_opWrErr == err) {
			MacMsg(kStrImageInUseTitle,
				kStrImageInUseMessage, falseblnr);
		} else {
			MacMsg(kStrOpenFailTitle, kStrOpenFailMessage, falseblnr);
		}
	}
}

LOCALFUNC tMacErr InsertADiskFromFileRef(FSSpec *spec)
{
	short refnum;
	tMacErr err;
	blnr locked = falseblnr;

	err = To_tMacErr(FSpOpenDF(spec, fsRdWrPerm, &refnum));
	switch (err) {
		case mnvm_permErr:
		case mnvm_wrPermErr:
		case mnvm_afpAccessDenied:
			locked = trueblnr;
			err = To_tMacErr(FSpOpenDF(spec, fsRdPerm, &refnum));
			break;
		default:
			break;
	}
	if (mnvm_noErr == err) {
		err = Sony_Insert0(refnum, locked, NULL);
	}

	return err;
}

#if HaveCPUfamM68K
LOCALFUNC tMacErr InsertADiskFromNamevRef(ConstStr255Param fileName,
	short vRefNum)
{
	ParamBlockRec R;
	tMacErr err;
	blnr locked = falseblnr;

	R.ioParam.ioCompletion = NULL;
	R.ioParam.ioNamePtr = (StringPtr)fileName;
	R.ioParam.ioVRefNum = vRefNum;
	R.ioParam.ioVersNum = 0;
	R.ioParam.ioPermssn = fsRdWrPerm;
	R.ioParam.ioMisc = NULL;
	err = To_tMacErr(PBOpen(&R, false));
	switch (err) {
		case mnvm_permErr:
		case mnvm_wrPermErr:
		case mnvm_afpAccessDenied:
			locked = trueblnr;
			R.ioParam.ioPermssn = fsRdPerm;
			err = To_tMacErr(PBOpen(&R, false));
			break;
		default:
			break;
	}
	if (mnvm_noErr == err) {
		err = Sony_Insert0(R.ioParam.ioRefNum, locked, (ps3p)fileName);
	}

	return err;
}
#endif

LOCALFUNC tMacErr LoadMacRomFromRefNum(short refnum)
{
	/*
		load the ROM image file into ptr ROM
	*/
	tMacErr err;
	long count = kROM_Size;

	if (mnvm_noErr != (err = To_tMacErr(
		FSRead(refnum, &count, ROM))))
	{
		if (mnvm_eofErr == err) {
			MacMsgOverride(kStrShortROMTitle, kStrShortROMMessage);
		} else {
			MacMsgOverride(kStrNoReadROMTitle, kStrNoReadROMMessage);
		}
	} else
	{
		err = ROM_IsValid();
	}

	return err;
}

LOCALFUNC tMacErr LoadMacRomFromFSSpec(FSSpec *spec)
{
	tMacErr err;
	short refnum;

	if (mnvm_noErr == (err =
		To_tMacErr(FSpOpenDF(spec, fsRdPerm, &refnum))))
	{
		err = LoadMacRomFromRefNum(refnum);
		(void) FSClose(refnum);
	}

	return err;
}

#if HaveCPUfamM68K
LOCALFUNC tMacErr LoadMacRomFromNamevRef(ConstStr255Param fileName,
	short vRefNum)
{
	tMacErr err;
	ParamBlockRec R;

	R.ioParam.ioCompletion = NULL;
	R.ioParam.ioNamePtr = (StringPtr)fileName;
	R.ioParam.ioVRefNum = vRefNum;
	R.ioParam.ioVersNum = 0;
	R.ioParam.ioPermssn = fsRdPerm;
	R.ioParam.ioMisc = NULL;
	if (mnvm_noErr == (err = To_tMacErr(PBOpen(&R, false)))) {
		err = LoadMacRomFromRefNum(R.ioParam.ioRefNum);
		(void) FSClose(R.ioParam.ioRefNum);
	}

	return err;
}
#endif

#if HaveCPUfamM68K
LOCALFUNC tMacErr InsertADiskFromNamevRef1(ConstStr255Param fileName,
	short vRefNum)
{
	tMacErr err;

	if (! ROM_loaded) {
		err = LoadMacRomFromNamevRef(fileName, vRefNum);
	} else {
		err = InsertADiskFromNamevRef(fileName, vRefNum);
	}

	return err;
}
#endif

LOCALFUNC tMacErr InsertADiskOrAliasFromSpec(FSSpec *spec,
	blnr MaybeROM, blnr MaybeAlias)
{
	Boolean isFolder;
	Boolean isAlias;
	tMacErr err;

	if ((! MaybeAlias)
		|| CheckSaveMacErr(ResolveAliasFile(spec, true,
			&isFolder, &isAlias)))
	{
		if (MaybeROM && ! ROM_loaded) {
			err = LoadMacRomFromFSSpec(spec);
		} else {
			err = InsertADiskFromFileRef(spec);
		}
	}

	return err;
}

LOCALFUNC tMacErr InsertDisksFromDocList(AEDescList *docList)
{
	tMacErr err = mnvm_noErr;
	long itemsInList;
	long index;
	AEKeyword keyword;
	DescType typeCode;
	FSSpec spec;
	Size actualSize;

	if (CheckSaveMacErr(AECountItems(docList, &itemsInList))) {
		for (index = 1; index <= itemsInList; ++index) {
			if (CheckSaveMacErr(AEGetNthPtr(docList, index, typeFSS,
				&keyword, &typeCode, (Ptr)&spec, sizeof(FSSpec),
				&actualSize)))
			if (CheckSavetMacErr(InsertADiskOrAliasFromSpec(&spec,
				trueblnr, falseblnr)))
			{
			}
			if (mnvm_noErr != err) {
				goto label_fail;
			}
		}
	}

label_fail:
	return err;
}

LOCALFUNC tMacErr InsertADiskFromNameEtc(MyDir_R *d,
	ConstStr255Param fileName)
{
	tMacErr err;

#if HaveCPUfamM68K
	if (! HaveFSSpecCallsAvail()) {
		err = InsertADiskFromNamevRef(fileName, d->VRefNum);
	} else
#endif
	{
		FSSpec spec;

		if (CheckSaveMacErr(
			FSMakeFSSpec(d->VRefNum, d->DirId, fileName, &spec)))
		{
			err = InsertADiskOrAliasFromSpec(&spec,
				falseblnr, trueblnr);
		}
	}

	return err;
}

#if NavigationAvail
pascal Boolean NavigationFilterProc(
	AEDesc* theItem, void* info, void* NavCallBackUserData,
	NavFilterModes theNavFilterModes);
pascal Boolean NavigationFilterProc(
	AEDesc* theItem, void* info, void* NavCallBackUserData,
	NavFilterModes theNavFilterModes)
{
	Boolean display = true;
	NavFileOrFolderInfo* theInfo = (NavFileOrFolderInfo*)info;
	UnusedParam(theNavFilterModes);
	UnusedParam(NavCallBackUserData);

	if (typeFSS == theItem->descriptorType) {
		if (! theInfo->isFolder) {
			/*
				use:
					'theInfo->fileAndFolder.fileInfo.finderInfo.fdType'
				to check for the file type you want to filter.
			*/
		}
	}
	return display;
}
#endif


#if NavigationAvail
pascal void NavigationEventProc(
	NavEventCallbackMessage callBackSelector,
	NavCBRecPtr callBackParms, void *NavCallBackUserData);
pascal void NavigationEventProc(
	NavEventCallbackMessage callBackSelector,
	NavCBRecPtr callBackParms, void *NavCallBackUserData)
{
	UnusedParam(NavCallBackUserData);

	if (kNavCBEvent == callBackSelector) {
		switch (callBackParms->eventData.eventDataParms.event->what) {
			case updateEvt:
				{
					WindowPtr which =
						(WindowPtr)callBackParms
							->eventData.eventDataParms.event
							->message;

					BeginUpdate(which);

					if (which == gMyMainWindow) {
						Update_Screen();
					}

					EndUpdate(which);
				}
				break;
		}
	}
}
#endif

#define PStrConstBlank ((ps3p)"\000")

LOCALPROC InsertADisk0(void)
{
#if NavigationAvail
#define MyDisposeNavEventUPP(userUPP) \
	DisposeRoutineDescriptor(userUPP)
#define MyDisposeNavObjectFilterUPP(userUPP) \
	DisposeRoutineDescriptor(userUPP)
#define MyNewNavObjectFilterUPP NewNavObjectFilterProc
#define MyNewNavEventUPP NewNavEventProc

	if (HaveNavServicesAvail()) {
		NavReplyRecord theReply;
		NavDialogOptions dialogOptions;
		OSErr theErr = noErr;
		NavTypeListHandle openList = NULL;
		NavObjectFilterUPP filterUPP =
			MyNewNavObjectFilterUPP(
				/* (NavObjectFilterProcPtr) */ NavigationFilterProc);
		NavEventUPP eventUPP = MyNewNavEventUPP(
			/* (NavEventProcPtr) */ NavigationEventProc);

		theErr = NavGetDefaultDialogOptions(&dialogOptions);

		dialogOptions.dialogOptionFlags |= kNavDontAutoTranslate;
		/*
			dialogOptions.dialogOptionFlags &= ~ kNavAllowMultipleFiles;
		*/
		dialogOptions.dialogOptionFlags &= ~ kNavAllowPreviews;

		MyBeginDialog();
		theErr = NavGetFile(NULL,
						&theReply,
						&dialogOptions,
						/* NULL */ eventUPP,
						NULL,
						filterUPP,
						(NavTypeListHandle)openList,
						NULL);
		MyEndDialog();

		MyDisposeNavObjectFilterUPP(filterUPP);
		MyDisposeNavEventUPP(eventUPP);


		if (noErr == theErr) {
			if (theReply.validRecord) {
				ReportStandardOpenDiskError(InsertDisksFromDocList(
					&theReply.selection));
			}

			NavDisposeReply(&theReply);
		}

	} else
#endif
#if HaveCPUfamM68K
	if (! HaveFSSpecCallsAvail()) {
		Point where;
		SFReply reply;

		where.h = 50;
		where.v = 50;
		MyBeginDialog();
		SFGetFile(*(Point *)&where, PStrConstBlank, NULL,
			-1 /* kNumFileTypes */, NULL /* fileTypes */,
			NULL, &reply);
		MyEndDialog();
		if (reply.good) {
			ReportStandardOpenDiskError(
				InsertADiskFromNamevRef1(reply.fName, reply.vRefNum));
		}
	} else
#endif
	{
		StandardFileReply reply;

		MyBeginDialog();
		StandardGetFile(0L, -1, 0L, &reply);
		MyEndDialog();
		if (reply.sfGood) {
			ReportStandardOpenDiskError(
				InsertADiskOrAliasFromSpec(&reply.sfFile,
					trueblnr, falseblnr));
		}
	}
}

#ifndef MyAppIsBundle
#define MyAppIsBundle 0
#endif

LOCALVAR MyDir_R MyDatDir;

#if MyAppIsBundle
LOCALFUNC blnr DirectorySpec2DirId(FSSpec *spec, long *dirID)
{
	CInfoPBRec b;

	b.hFileInfo.ioCompletion = NULL;
	b.hFileInfo.ioNamePtr = (StringPtr)spec->name;
	b.hFileInfo.ioVRefNum = spec->vRefNum;
	b.dirInfo.ioFDirIndex = 0;
	b.dirInfo.ioDrDirID = spec->parID;
	if (noErr == PBGetCatInfo(&b, false)) {
		*dirID = b.dirInfo.ioDrDirID;
		return trueblnr;
	} else {
		return falseblnr;
	}
}
#endif

#if MyAppIsBundle
LOCALFUNC blnr FindNamedChildDirId(short TrueParentVol,
	long ParentDirId, StringPtr ChildName,
	short *TrueChildVol, long *ChildDirId)
{

	FSSpec temp_spec;
	Boolean isFolder;
	Boolean isAlias;

	if (noErr == FSMakeFSSpec(TrueParentVol, ParentDirId,
		ChildName, &temp_spec))
	if (noErr == ResolveAliasFile(&temp_spec, true,
		&isFolder, &isAlias))
	if (isFolder)
	if (DirectorySpec2DirId(&temp_spec, ChildDirId))
	{
		*TrueChildVol = temp_spec.vRefNum;
		return trueblnr;
	}
	return falseblnr;
}
#endif

LOCALFUNC blnr InitMyApplInfo(void)
{
#if HaveCPUfamM68K
	if (! HaveFSSpecCallsAvail()) {
		if (noErr == GetVol(NULL, &MyDatDir.VRefNum)) {
			MyDatDir.DirId = 0;
			return trueblnr;
		}
	} else
#endif
	{
		FCBPBRec pb;
		Str255 fileName;

		pb.ioCompletion = NULL;
		pb.ioNamePtr = fileName;
		pb.ioVRefNum = 0;
		pb.ioRefNum = CurResFile();
		pb.ioFCBIndx = 0;
		if (noErr == PBGetFCBInfoSync(&pb)) {
			MyDatDir.VRefNum = pb.ioFCBVRefNum;
			MyDatDir.DirId = pb.ioFCBParID;
			return trueblnr;
		}
	}

	return falseblnr;
}

LOCALFUNC tMacErr MyDirFromWD_v2(short VRefNum, MyDir_R *d)
{
	tMacErr err;
	Str63 s;
	WDPBRec pb;

#if Support64kROM
	if (Have64kROM()) {
		d->VRefNum = VRefNum;
		d->DirId = 0;
		err = mnvm_noErr;
	} else
#endif
	{
		pb.ioCompletion = NULL;
		pb.ioNamePtr = s;
		pb.ioVRefNum = VRefNum;
		pb.ioWDIndex = 0;
		pb.ioWDProcID = 0;
		err = To_tMacErr(PBGetWDInfoSync(&pb));
		if (mnvm_noErr == err) {
			d->VRefNum = pb.ioWDVRefNum;
			d->DirId = pb.ioWDDirID;
		}
	}

	return err;
}

LOCALFUNC tMacErr FindPrefFolder(MyDir_R *d)
{
	tMacErr err;
	long reply;

	if (HaveGestaltAvail()
		&& (noErr == Gestalt(gestaltFindFolderAttr, &reply))
		&& TestBit(reply, gestaltFindFolderPresent)
		)
	{
		err = To_tMacErr(FindFolder(
			kOnSystemDisk,
			kPreferencesFolderType,
			kDontCreateFolder,
			&d->VRefNum,
			&d->DirId));
	} else {
		SysEnvRec info;

		err = To_tMacErr(SysEnvirons(1, &info));
		if (mnvm_noErr == err) {
			err = MyDirFromWD_v2(info.sysVRefNum, d);
		}
	}

	return err;
}

#define CatInfoIsFolder(cPB) \
	(((cPB)->hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0)

#define PStrLength(s) (*(s))
#define SizeOfListMyChar(n) (n)
#define PStrToTotSize(s) (SizeOfListMyChar(PStrLength(s) + 1))
	/* + 1 for length byte */

LOCALPROC PStrCopy(ps3p r, ps3p s)
{
	MyMoveBytes((anyp)s, (anyp)r, PStrToTotSize(s));
}

LOCALFUNC tMacErr MyFindNamedChildDir_v2(MyDir_R *src_d, StringPtr s,
	MyDir_R *dst_d)
{
	tMacErr err;
	Str255 NameBuffer;
	CInfoPBRec cPB;

	cPB.hFileInfo.ioCompletion = NULL;
	cPB.hFileInfo.ioVRefNum = src_d->VRefNum;
	cPB.dirInfo.ioDrDirID = src_d->DirId;
	cPB.hFileInfo.ioNamePtr = NameBuffer;
	PStrCopy(NameBuffer, s);
	cPB.dirInfo.ioFDirIndex = 0;

	err = To_tMacErr(PBGetCatInfoSync(&cPB));

	if (mnvm_noErr == err) {
		if (! CatInfoIsFolder(&cPB)) {
			err = mnvm_dirNFErr;
		} else {
			dst_d->VRefNum = cPB.hFileInfo.ioVRefNum;
			dst_d->DirId = cPB.dirInfo.ioDrDirID;
		}
	}

	return err;
}

LOCALFUNC tMacErr MyResolveAliasDir_v2(MyDir_R *src_d, StringPtr s,
	MyDir_R *dst_d)
{
	tMacErr err;
	FSSpec spec;
	Boolean isFolder;
	Boolean isAlias;
	MyDir_R src2_d;

	spec.vRefNum = src_d->VRefNum;
	spec.parID = src_d->DirId;
	PStrCopy(spec.name, s);
	err = To_tMacErr(
		ResolveAliasFile(&spec, true, &isFolder, &isAlias));
	if (mnvm_noErr == err) {
		if (! isAlias) {
			err = mnvm_dirNFErr;
		} else {
			src2_d.VRefNum = spec.vRefNum;
			src2_d.DirId = spec.parID;
			err = MyFindNamedChildDir_v2(&src2_d, spec.name, dst_d);
		}
	}

	return err;
}

LOCALFUNC tMacErr MyResolveNamedChildDir_v2(MyDir_R *src_d, StringPtr s,
	MyDir_R *dst_d)
{
	tMacErr err;

	err = MyFindNamedChildDir_v2(src_d, s, dst_d);
	if (mnvm_dirNFErr == err) {
		if (HaveAliasMgrAvail()) {
			err = MyResolveAliasDir_v2(src_d, s, dst_d);
		}
	}

	return err;
}

LOCALFUNC tMacErr OpenNamedFileInFolderCStr(MyDir_R *d,
	char *s, short *refnum)
{
	Str255 fileName;

	PStrFromCStr(fileName, s);
	return OpenNamedFileInFolder(d, fileName, refnum);
}

LOCALFUNC tMacErr MyResolveNamedChildDirCStr(MyDir_R *src_d,
	char *s, MyDir_R *dst_d)
{
	Str255 fileName;

	PStrFromCStr(fileName, s);
	return MyResolveNamedChildDir_v2(src_d, fileName, dst_d);
}

LOCALFUNC tMacErr LoadMacRomFromNameFolder(MyDir_R *d,
	char *s)
{
	tMacErr err;
	short refnum;

	if (mnvm_noErr == (err =
		OpenNamedFileInFolderCStr(d, s, &refnum)))
	{
		err = LoadMacRomFromRefNum(refnum);
		(void) FSClose(refnum);
	}

	return err;
}

LOCALFUNC tMacErr LoadMacRomFromPrefDir(void)
{
	tMacErr err;
	MyDir_R PrefRef;
	MyDir_R GryphelRef;
	MyDir_R ROMsRef;

	if (mnvm_noErr == (err = FindPrefFolder(&PrefRef)))
	if (mnvm_noErr == (err = MyResolveNamedChildDirCStr(&PrefRef,
		"Gryphel", &GryphelRef)))
	if (mnvm_noErr == (err = MyResolveNamedChildDirCStr(&GryphelRef,
		"mnvm_rom", &ROMsRef)))
	if (mnvm_noErr == (err = LoadMacRomFromNameFolder(&ROMsRef,
		RomFileName)))
	{
		/* ok */
	}

	return err;
}

LOCALFUNC blnr LoadMacRom(void)
{
	tMacErr err;

	if (mnvm_fnfErr == (err =
		LoadMacRomFromNameFolder(&MyDatDir, RomFileName)))
	if (mnvm_fnfErr == (err =
		LoadMacRomFromPrefDir()))
	{
	}

	return trueblnr; /* keep launching Mini vMac, regardless */
}

LOCALFUNC blnr Sony_InsertIth(int i)
{
	if ((i > 9) || ! FirstFreeDisk(nullpr)) {
		return falseblnr;
	} else {
		Str255 s;
		tMacErr err = mnvm_noErr;

		PStrFromCStr(s, "disk?.dsk");

		s[5] = '0' + i;
		if (! CheckSavetMacErr(InsertADiskFromNameEtc(&MyDatDir, s))) {
			if (mnvm_fnfErr != err) {
				ReportStandardOpenDiskError(err);
			}
			return falseblnr;
		}

		return trueblnr;
	}
}

LOCALFUNC blnr LoadInitialImages(void)
{
	int i;

	for (i = 1; Sony_InsertIth(i); ++i) {
		/* stop on first error (including file not found) */
	}

	return trueblnr;
}

#if IncludeSonyNew
LOCALFUNC tMacErr WriteZero(SInt16 refnum, ui5b L)
{
#define ZeroBufferSize 2048
	tMacErr err;
	ui5b i;
	ui3b buffer[ZeroBufferSize];

	if (CheckSaveMacErr(SetFPos(refnum, fsFromStart, 0))) {

		for (i = 0; i < ZeroBufferSize; ++i) {
			buffer[i] = 0;
		}
		while (L > 0) {
			i = (L > ZeroBufferSize) ? ZeroBufferSize : L;
			err = To_tMacErr(FSWrite(refnum, (long *)&i, buffer));
			if (mnvm_noErr != err) {
				goto label_fail;
			}
			L -= i;
		}
	}

label_fail:
	return err;
}
#endif

#if HaveCPUfamM68K && IncludeSonyNew
LOCALPROC MakeNewDiskFromNamevRef(ps3p Name, short vRefNum,
	ui5b L)
{
	short refNum;
	tMacErr err;

	err = To_tMacErr(Create(Name, vRefNum, '????', '????'));
	if (mnvm_dupFNErr == err) {
		if (CheckSaveMacErr(FSDelete(Name, vRefNum))) {
			err = To_tMacErr(Create(Name, vRefNum, '????', '????'));
		}
	}
	if (mnvm_noErr == err) {
		if (CheckSaveMacErr(FSOpen(Name, vRefNum, &refNum))) {
			if (CheckSaveMacErr(SetEOF(refNum, L))) {
				if (CheckSavetMacErr(WriteZero(refNum, L))) {
					err = Sony_Insert0(refNum, falseblnr, Name);
					ReportStandardOpenDiskError(err);
					refNum = NotAfileRef;
				}
			}
			if (NotAfileRef != refNum) {
				(void) FSClose(refNum);
			}
		}
		if (mnvm_noErr != err) {
			(void) FSDelete(Name, vRefNum);
		}
	}
}
#endif

#if IncludeSonyNew
LOCALPROC MakeNewDiskFromSpec(FSSpec *NewFileSpec,
	ui5b L)
{
	short refNum;
	tMacErr err;

	err = To_tMacErr(FSpCreate(NewFileSpec,
		'????', '????', smSystemScript));
	if (mnvm_dupFNErr == err) {
		err = To_tMacErr(FSpDelete(NewFileSpec));
		if (mnvm_noErr == err) {
			err = To_tMacErr(FSpCreate(NewFileSpec,
				'????', '????', smSystemScript));
		}
	}
	if (mnvm_noErr == err) {
		if (CheckSaveMacErr(
			FSpOpenDF(NewFileSpec, fsRdWrPerm, &refNum)))
		{
			if (CheckSaveMacErr(SetEOF(refNum, L))) {
				if (CheckSavetMacErr(WriteZero(refNum, L))) {
					err = Sony_Insert0(refNum, falseblnr, NULL);
					ReportStandardOpenDiskError(err);
					refNum = NotAfileRef;
				}
			}
			if (NotAfileRef != refNum) {
				(void) FSClose(refNum);
			}
		}
		if (mnvm_noErr != err) {
			(void) FSpDelete(NewFileSpec);
		}
	}
}
#endif

#if UseActvFile || (IncludeSonyNew && ! SaveDialogEnable)
LOCALFUNC tMacErr MyMakeNamedDir_v2(MyDir_R *d, StringPtr s,
	MyDir_R *new_d)
{
	tMacErr err;
	HParamBlockRec r;

	r.fileParam.ioCompletion = NULL;
	r.fileParam.ioVRefNum = d->VRefNum;
	r.fileParam.ioDirID = d->DirId;
	r.fileParam.ioNamePtr = s;
	err = To_tMacErr(PBDirCreateSync(&r));
	if (mnvm_noErr == err) {
		new_d->VRefNum = d->VRefNum;
		new_d->DirId = r.fileParam.ioDirID;
	}

	return err;
}
#endif

#if UseActvFile || (IncludeSonyNew && ! SaveDialogEnable)
LOCALFUNC tMacErr FindOrMakeMakeNamedDir_v2(MyDir_R *new_d,
	MyDir_R *d, StringPtr s)
{
	tMacErr err;

	err = MyResolveNamedChildDir_v2(d, s, new_d);
	if (mnvm_fnfErr == err) {
		err = MyMakeNamedDir_v2(d, s, new_d);
	}

	return err;
}
#endif

#if UseActvFile || (IncludeSonyNew && ! SaveDialogEnable)
LOCALFUNC tMacErr FindOrMakeChildDirCStr(MyDir_R *new_d,
	MyDir_R *d, char *name)
{
	Str255 s;

	PStrFromCStr(s, name);
	return FindOrMakeMakeNamedDir_v2(new_d, d, s);
}
#endif

#if IncludeSonyNew
LOCALPROC MakeNewDisk(ui5b L, Handle NewDiskName)
{
#if SaveDialogEnable
	OSErr theErr;

#if NavigationAvail
	if (HaveNavServicesAvail()) {
		NavReplyRecord theReply;
		NavDialogOptions dialogOptions;
		NavEventUPP eventUPP = MyNewNavEventUPP(
			/* (NavEventProcPtr) */ NavigationEventProc);

		theErr = NavGetDefaultDialogOptions(&dialogOptions);
		dialogOptions.dialogOptionFlags |= kNavNoTypePopup;
#if IncludeSonyNameNew
		if (NewDiskName != NULL) {
			PStrFromHandle(dialogOptions.savedFileName,
				NewDiskName, 255);
		}
#endif
		MyBeginDialog();
		theErr = NavPutFile(NULL, &theReply, &dialogOptions,
			/* NULL */ eventUPP, '????', '????', NULL);
		MyEndDialog();

		MyDisposeNavEventUPP(eventUPP);

		if (noErr == theErr) {
			if (theReply.validRecord) {
				long itemsInList;
				AEKeyword keyword;
				DescType typeCode;
				Size actualSize;
				FSSpec NewFileSpec;

				if (noErr ==
					AECountItems(&theReply.selection, &itemsInList))
				if (1 == itemsInList)
				if (noErr == AEGetNthPtr(&theReply.selection,
					1, typeFSS, &keyword, &typeCode,
					(Ptr)&NewFileSpec, sizeof(FSSpec), &actualSize))
				{
					MakeNewDiskFromSpec(&NewFileSpec, L);
				}
			}
			NavDisposeReply(&theReply);
		}
	} else
#endif
	{
		Str255 Title;
		Str255 prompt;

#if IncludeSonyNameNew
		if (NewDiskName != NULL) {
			PStrFromHandle(Title, NewDiskName, 255);
		} else
#endif
		{
			NativeStrFromCStr(Title, "untitled", falseblnr);
		}
		NativeStrFromCStr(prompt, "Please select a file", falseblnr);

#if HaveCPUfamM68K
		if (! HaveFSSpecCallsAvail()) {
			Point where;
			SFReply reply;

			where.h = 50;
			where.v = 50;
			MyBeginDialog();
			SFPutFile(*(Point *)&where, prompt, Title, NULL, &reply);
			MyEndDialog();

			if (reply.good) {
				MakeNewDiskFromNamevRef(reply.fName,
					reply.vRefNum, L);
			}
		} else
#endif
		{
			StandardFileReply reply;

			MyBeginDialog();
			StandardPutFile(prompt, Title, &reply);
			MyEndDialog();

			if (reply.sfGood) {
				MakeNewDiskFromSpec(&reply.sfFile, L);
			}
		}
	}
#else /* SaveDialogEnable */
	tMacErr err;
	Str255 Title;
	MyDir_R OutDir;
	FSSpec spec;

#if IncludeSonyNameNew
	if (NewDiskName != NULL) {
		PStrFromHandle(Title, NewDiskName, 255);
	} else
#endif
	{
		NativeStrFromCStr(Title, "untitled", falseblnr);
	}

	if (mnvm_noErr == (err = FindOrMakeChildDirCStr(&OutDir,
		&MyDatDir, "out")))
	{
#if HaveCPUfamM68K
		if (! HaveFSSpecCallsAvail()) {
			MakeNewDiskFromNamevRef(Title, OutDir.VRefNum, L);
		} else
#endif
		{
			err = To_tMacErr(FSMakeFSSpec(OutDir.VRefNum, OutDir.DirId,
				Title, &spec));
			if ((mnvm_noErr == err) || (mnvm_fnfErr == err)) {
				MakeNewDiskFromSpec(&spec, L);
			}
		}
	}
#endif /* SaveDialogEnable */
}
#endif

#if UseActvFile

LOCALFUNC tMacErr MyCreateFile_v2(MyDir_R *d, StringPtr s)
{
	tMacErr err;
	HParamBlockRec r;

	r.fileParam.ioFlVersNum = 0;
		/*
			Think reference says to do this,
			but not Inside Mac IV
		*/

	r.fileParam.ioCompletion = NULL;
	r.fileParam.ioNamePtr = s;
	r.fileParam.ioVRefNum = d->VRefNum;
	r.fileParam.ioFVersNum = 0; /* needed if MFS volume */

#if Support64kROM
	if (Have64kROM()) {
		err = To_tMacErr(PBCreateSync((ParamBlockRec *)&r));
	} else
#endif
	{
		r.fileParam.ioDirID = d->DirId;
		err = To_tMacErr(PBHCreateSync(&r));
	}

	return err;
}

LOCALFUNC tMacErr MyDeleteFile_v2(MyDir_R *d, StringPtr s)
{
	tMacErr err;
	HParamBlockRec r;

	r.fileParam.ioCompletion = NULL;
	r.fileParam.ioVRefNum = d->VRefNum;
	r.fileParam.ioNamePtr = s;
	r.fileParam.ioFVersNum = 0; /* needed if MFS volume */

#if Support64kROM
	if (Have64kROM()) {
		err = To_tMacErr(PBDeleteSync((ParamBlockRec *)&r));
	} else
#endif
	{
		r.fileParam.ioDirID = d->DirId;
		err = To_tMacErr(PBHDeleteSync(&r));
	}

	return err;
}

LOCALFUNC tMacErr MyCreateFileOverWrite_v2(MyDir_R *d, StringPtr s)
{
	tMacErr err;

	err = MyCreateFile_v2(d, s);
	if (mnvm_dupFNErr == err) {
		if (mnvm_noErr == (err = MyDeleteFile_v2(d, s))) {
			err = MyCreateFile_v2(d, s);
		}
	}

	return err;
}

LOCALFUNC tMacErr MyFileOpen_v2(MyDir_R *d, StringPtr s,
	char Permssn, short *refnum)
{
	tMacErr err;
	HParamBlockRec r;

	r.ioParam.ioCompletion = NULL;
	r.ioParam.ioNamePtr = s;
	r.ioParam.ioVRefNum = d->VRefNum;
	r.ioParam.ioPermssn = Permssn;
	r.ioParam.ioMisc = 0; /* use volume buffer */
	r.ioParam.ioVersNum = 0; /* needed if MFS volume */

#if Support64kROM
	if (Have64kROM()) {
		err = To_tMacErr(PBOpenSync((ParamBlockRec *)&r));
	} else
#endif
	{
		r.fileParam.ioDirID = d->DirId;
		err = To_tMacErr(PBHOpenSync(&r));
	}

	if (noErr == err) {
		*refnum = r.ioParam.ioRefNum;
		/*
			Don't change *refnum unless file opened,
			so can initialize to NotAfileRef, and
			compare later before closing in uninit.
		*/
	}
	return err;
}

LOCALFUNC tMacErr MyFileOpenWrite_v2(MyDir_R *d, StringPtr s,
	short *refnum)
{
	return MyFileOpen_v2(d, s, (char)fsWrPerm, refnum);
}

LOCALFUNC tMacErr MyOpenOverWriteFile_v2(MyDir_R *d, StringPtr s,
	short *refnum)
{
	tMacErr err;

	err = MyCreateFileOverWrite_v2(d, s);
	if (mnvm_noErr == err) {
		err = MyFileOpenWrite_v2(d, s, refnum);

		if (mnvm_noErr != err) {
			(void) MyDeleteFile_v2(d, s);
				/* ignore any error, since already got one */
		}
	}

	return err;
}

LOCALFUNC tMacErr MyOpenOverWriteFileCStr(MyDir_R *d, char *name,
	short *refnum)
{
	Str255 s;

	PStrFromCStr(s, name);
	return MyOpenOverWriteFile_v2(d, s, refnum);
}

#define ActvCodeFileName "act_1"

LOCALFUNC tMacErr OpenActvCodeFile(short *refnum)
{
	tMacErr err;
	MyDir_R PrefRef;
	MyDir_R GryphelRef;
	MyDir_R ActRef;

	if (mnvm_noErr == (err = FindPrefFolder(&PrefRef)))
	if (mnvm_noErr == (err = MyResolveNamedChildDirCStr(&PrefRef,
		"Gryphel", &GryphelRef)))
	if (mnvm_noErr == (err = MyResolveNamedChildDirCStr(&GryphelRef,
		"mnvm_act", &ActRef)))
	if (mnvm_noErr == (err = OpenNamedFileInFolderCStr(&ActRef,
		ActvCodeFileName, refnum)))
	{
		/* ok */
	}

	return err;
}

LOCALFUNC tMacErr ActvCodeFileLoad(ui3p p)
{
	tMacErr err;
	short refnum;

	if (CheckSavetMacErr(OpenActvCodeFile(&refnum))) {
		long count = ActvCodeFileLen;
		err = To_tMacErr(FSRead(refnum, &count, p));
		(void) FSClose(refnum);
	}

	return err;
}

LOCALFUNC tMacErr ActvCodeFileSave(ui3p p)
{
	tMacErr err;
	short refnum;
	MyDir_R PrefRef;
	MyDir_R GryphelRef;
	MyDir_R ActRef;
	long count = ActvCodeFileLen;

	if (mnvm_noErr == (err = FindPrefFolder(&PrefRef)))
	if (mnvm_noErr == (err = FindOrMakeChildDirCStr(&GryphelRef,
		&PrefRef, "Gryphel")))
	if (mnvm_noErr == (err = FindOrMakeChildDirCStr(&ActRef,
		&GryphelRef, "mnvm_act")))
	if (mnvm_noErr == (err = MyOpenOverWriteFileCStr(&ActRef,
		ActvCodeFileName, &refnum)))
	{
		err = To_tMacErr(FSWrite(refnum, &count, p));
		(void) FSClose(refnum);
	}

	return err;
	/* return mnvm_miscErr; */
}

#endif /* UseActvFile */

#define openOnly 1
#define openPrint 2

LOCALFUNC blnr GotRequiredParams(AppleEvent *theAppleEvent)
{
	DescType typeCode;
	Size actualSize;
	OSErr theErr;

	theErr = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr,
				typeWildCard, &typeCode, NULL, 0, &actualSize);
	if (errAEDescNotFound == theErr) { /* No more required params. */
		return trueblnr;
	} else if (noErr == theErr) { /* More required params! */
		return /* CheckSysCode(errAEEventNotHandled) */ falseblnr;
	} else { /* Unexpected Error! */
		return /* CheckSysCode(theErr) */ falseblnr;
	}
}

LOCALFUNC blnr GotRequiredParams0(AppleEvent *theAppleEvent)
{
	DescType typeCode;
	Size actualSize;
	OSErr theErr;

	theErr = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr,
				typeWildCard, &typeCode, NULL, 0, &actualSize);
	if (errAEDescNotFound == theErr) { /* No more required params. */
		return trueblnr;
	} else if (noErr == theErr) { /* More required params! */
		return trueblnr; /* errAEEventNotHandled; */ /*^*/
	} else { /* Unexpected Error! */
		return /* CheckSysCode(theErr) */ falseblnr;
	}
}

/* call back */ static pascal OSErr OpenOrPrintFiles(
	AppleEvent *theAppleEvent, AppleEvent *reply, long aRefCon)
{
	/*
		Adapted from IM VI: AppleEvent Manager:
		Handling Required AppleEvents
	*/
	AEDescList docList;

	UnusedParam(reply);
	UnusedParam(aRefCon);
	/* put the direct parameter (a list of descriptors) into docList */
	if (noErr == (AEGetParamDesc(theAppleEvent,
		keyDirectObject, typeAEList, &docList)))
	{
		if (GotRequiredParams0(theAppleEvent)) {
			/* Check for missing required parameters */
			/* printIt = (openPrint == aRefCon) */
			ReportStandardOpenDiskError(
				InsertDisksFromDocList(&docList));
		}
		/* vCheckSysCode */ (void) (AEDisposeDesc(&docList));
	}
	return /* GetASysResultCode() */ 0;
}

/* call back */ static pascal OSErr DoOpenEvent(
	AppleEvent *theAppleEvent, AppleEvent *reply, long aRefCon)
/*
	This is the alternative to getting an
	open document event on startup.
*/
{
	UnusedParam(reply);
	UnusedParam(aRefCon);
	if (GotRequiredParams0(theAppleEvent)) {
	}
	return /* GetASysResultCode() */ 0;
		/* Make sure there are no additional "required" parameters. */
}


/* call back */ static pascal OSErr DoQuitEvent(
	AppleEvent *theAppleEvent, AppleEvent *reply, long aRefCon)
{
	UnusedParam(reply);
	UnusedParam(aRefCon);
	if (GotRequiredParams(theAppleEvent)) {
		RequestMacOff = trueblnr;
	}

	return /* GetASysResultCode() */ 0;
}

#define MyNewAEEventHandlerUPP NewAEEventHandlerProc

LOCALFUNC blnr MyInstallEventHandler(AEEventClass theAEEventClass,
	AEEventID theAEEventID, ProcPtr p,
	long handlerRefcon, blnr isSysHandler)
{
	return noErr == (AEInstallEventHandler(theAEEventClass,
		theAEEventID,
#if /* useUPP */ 1
		MyNewAEEventHandlerUPP((AEEventHandlerProcPtr)p),
#else
		(AEEventHandlerUPP)p,
#endif
		handlerRefcon, isSysHandler));
}

LOCALPROC InstallAppleEventHandlers(void)
{
	if (noErr == AESetInteractionAllowed(kAEInteractWithLocal))
	if (MyInstallEventHandler(kCoreEventClass, kAEOpenApplication,
		(ProcPtr)DoOpenEvent, 0, falseblnr))
	if (MyInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
		(ProcPtr)OpenOrPrintFiles, openOnly, falseblnr))
	if (MyInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
		(ProcPtr)OpenOrPrintFiles, openPrint, falseblnr))
	if (MyInstallEventHandler(kCoreEventClass, kAEQuitApplication,
		(ProcPtr)DoQuitEvent, 0, falseblnr))
	{
	}
}

#if EnableDragDrop
static pascal OSErr GlobalTrackingHandler(short message,
	WindowRef pWindow, void *handlerRefCon, DragReference theDragRef)
{
	RgnHandle hilightRgn;
	Rect Bounds;

	UnusedParam(pWindow);
	UnusedParam(handlerRefCon);
	if (! ADialogIsUp) {
		switch(message) {
			case kDragTrackingEnterWindow:
				hilightRgn = NewRgn();
				if (hilightRgn != NULL) {
					SetScrnRectFromCoords(&Bounds,
						0, 0, vMacScreenHeight, vMacScreenWidth);
					RectRgn(hilightRgn, &Bounds);
					ShowDragHilite(theDragRef, hilightRgn, true);
					DisposeRgn(hilightRgn);
				}
				break;
			case kDragTrackingLeaveWindow:
				HideDragHilite(theDragRef);
				break;
		}
	}

	return noErr;
}
#endif

#if EnableDragDrop
static DragTrackingHandlerUPP gGlobalTrackingHandler = NULL;
#endif

#if EnableDragDrop
static pascal OSErr GlobalReceiveHandler(WindowRef pWindow,
	void *handlerRefCon, DragReference theDragRef)
{
	unsigned short items;
	unsigned short index;
	ItemReference theItem;
	Size SentSize;
	HFSFlavor r;

	UnusedParam(pWindow);
	UnusedParam(handlerRefCon);
	if (! ADialogIsUp)
	if (noErr == CountDragItems(theDragRef, &items))
	{
		for (index = 1; index <= items; ++index) {
			if (noErr == GetDragItemReferenceNumber(theDragRef,
				index, &theItem))
			if (noErr == GetFlavorDataSize(theDragRef,
				theItem, flavorTypeHFS, &SentSize))
				/*
					On very old macs SentSize might only be big enough
					to hold the actual file name. Have not seen this
					in OS X, but still leave the check
					as '<=' instead of '=='.
				*/
			if (SentSize <= sizeof(HFSFlavor))
			if (noErr == GetFlavorData(theDragRef, theItem,
				flavorTypeHFS, (Ptr)&r, &SentSize, 0))
			{
				ReportStandardOpenDiskError(
					InsertADiskOrAliasFromSpec(&r.fileSpec,
						trueblnr, trueblnr));
			}
		}

		if (gTrueBackgroundFlag) {
			ProcessSerialNumber currentProcess = {0, kCurrentProcess};

			(void) SetFrontProcess(&currentProcess);

			WantCmdOptOnReconnect = trueblnr;
		}
	}

	return noErr;
}
#endif

#if EnableDragDrop
static DragReceiveHandlerUPP gGlobalReceiveHandler = NULL;
#endif

#if EnableDragDrop
#define MyNewDragTrackingHandlerUPP NewDragTrackingHandlerProc
#define MyNewDragReceiveHandlerUPP NewDragReceiveHandlerProc
#if ! OPAQUE_UPP_TYPES
#define MyDisposeDragReceiveHandlerUPP(userUPP) \
	DisposeRoutineDescriptor(userUPP)
#define MyDisposeDragTrackingHandlerUPP(userUPP) \
	DisposeRoutineDescriptor(userUPP)
#else
#define MyDisposeDragReceiveHandlerUPP DisposeDragReceiveHandlerUPP
#define MyDisposeDragTrackingHandlerUPP DisposeDragTrackingHandlerUPP
#endif
#endif

#if EnableDragDrop
LOCALPROC UnPrepareForDragging(void)
{
	if (NULL != gGlobalReceiveHandler) {
		RemoveReceiveHandler(gGlobalReceiveHandler, gMyMainWindow);
		MyDisposeDragReceiveHandlerUPP(gGlobalReceiveHandler);
		gGlobalReceiveHandler = NULL;
	}
	if (NULL != gGlobalTrackingHandler) {
		RemoveTrackingHandler(gGlobalTrackingHandler, gMyMainWindow);
		MyDisposeDragTrackingHandlerUPP(gGlobalTrackingHandler);
		gGlobalTrackingHandler = NULL;
	}
}
#endif

#if EnableDragDrop
LOCALFUNC blnr PrepareForDragging(void)
{
	blnr IsOk = falseblnr;

	gGlobalTrackingHandler = MyNewDragTrackingHandlerUPP(
		GlobalTrackingHandler);
	if (gGlobalTrackingHandler != NULL) {
		gGlobalReceiveHandler = MyNewDragReceiveHandlerUPP(
			GlobalReceiveHandler);
		if (gGlobalReceiveHandler != NULL) {
			if (noErr == InstallTrackingHandler(gGlobalTrackingHandler,
				gMyMainWindow, nil))
			{
				if (noErr == InstallReceiveHandler(
					gGlobalReceiveHandler, gMyMainWindow, nil))
				{
					IsOk = trueblnr;
				}
			}
		}
	}

	return IsOk;
}
#endif

#if EnableMagnify
#define ScaleBuffSzMult (MyWindowScale * MyWindowScale)
#endif

LOCALFUNC blnr MyCreateNewWindow(Rect *Bounds, WindowPtr *theWindow)
{
	WindowPtr ResultWin;
	blnr IsOk = falseblnr;

	ResultWin = NewWindow(
		0L, Bounds, LMGetCurApName() /* "\pMini vMac" */, false,
		noGrowDocProc, /* Could use kWindowSimpleProc for Full Screen */
		(WindowPtr) -1, true, 0);
	if (ResultWin != NULL) {
		*theWindow = ResultWin;

		IsOk = trueblnr;
	}

	return IsOk;
}

LOCALPROC ZapMyWState(void)
{
	gMyMainWindow = NULL;
	gGlobalReceiveHandler = NULL;
	gGlobalTrackingHandler = NULL;
}

LOCALPROC CloseMainWindow(void)
{
	/*
		Dispose of anything set up by CreateMainWindow.
	*/

#if EnableDragDrop
	UnPrepareForDragging();
#endif

	if (gMyMainWindow != NULL) {
		DisposeWindow(gMyMainWindow);
		gMyMainWindow = NULL;
	}
}

enum {
	kMagStateNormal,
#if EnableMagnify
	kMagStateMagnifgy,
#endif
	kNumMagStates
};

#define kMagStateAuto kNumMagStates

#if MayNotFullScreen
LOCALVAR int CurWinIndx;
LOCALVAR blnr HavePositionWins[kNumMagStates];
LOCALVAR Point WinPositionWins[kNumMagStates];
#endif

LOCALFUNC blnr CreateMainWindow(void)
{
	/*
		Set up somewhere for us to draw the emulated screen and
		receive mouse input. i.e. usually a window, as is the case
		for this port.

		The window should not be resizeable.

		Should look at the current value of UseMagnify and
		UseFullScreen.

	*/
#if MayNotFullScreen
	int WinIndx;
#endif
	Rect MainScrnBounds;
	Rect AllScrnBounds;
	Rect NewWinRect;
	short leftPos;
	short topPos;
	short NewWindowHeight = vMacScreenHeight;
	short NewWindowWidth = vMacScreenWidth;
	blnr IsOk = falseblnr;

#if VarFullScreen
	if (UseFullScreen) {
		My_HideMenuBar();
	}  else {
		My_ShowMenuBar();
	}
#else
#if MayFullScreen
		My_HideMenuBar();
#endif
#endif

	MyGetGrayRgnBounds(&AllScrnBounds);
	MyGetScreenBitsBounds(&MainScrnBounds);

#if EnableMagnify
	if (UseMagnify) {
		NewWindowHeight *= MyWindowScale;
		NewWindowWidth *= MyWindowScale;
	}
#endif

	leftPos = MainScrnBounds.left
		+ ((MainScrnBounds.right - MainScrnBounds.left)
			- NewWindowWidth) / 2;
	topPos = MainScrnBounds.top
		+ ((MainScrnBounds.bottom - MainScrnBounds.top)
			- NewWindowHeight) / 2;
	if (leftPos < MainScrnBounds.left) {
		leftPos = MainScrnBounds.left;
	}
	if (topPos < MainScrnBounds.top) {
		topPos = MainScrnBounds.top;
	}

#if VarFullScreen
	if (UseFullScreen)
#endif
#if MayFullScreen
	{
		ViewHSize = MainScrnBounds.right - MainScrnBounds.left;
		ViewVSize = MainScrnBounds.bottom - MainScrnBounds.top;
#if EnableMagnify
		if (UseMagnify) {
			ViewHSize /= MyWindowScale;
			ViewVSize /= MyWindowScale;
		}
#endif
		if (ViewHSize >= vMacScreenWidth) {
			ViewHStart = 0;
			ViewHSize = vMacScreenWidth;
		} else {
			ViewHSize &= ~ 1;
		}
		if (ViewVSize >= vMacScreenHeight) {
			ViewVStart = 0;
			ViewVSize = vMacScreenHeight;
		} else {
			ViewVSize &= ~ 1;
		}
	}
#endif

	/* Create window rectangle and centre it on the screen */
	SetRect(&MainScrnBounds, 0, 0, NewWindowWidth, NewWindowHeight);
	OffsetRect(&MainScrnBounds, leftPos, topPos);

#if VarFullScreen
	if (UseFullScreen)
#endif
#if MayFullScreen
	{
		NewWinRect = AllScrnBounds;
	}
#endif
#if VarFullScreen
	else
#endif
#if MayNotFullScreen
	{
#if EnableMagnify
		if (UseMagnify) {
			WinIndx = kMagStateMagnifgy;
		} else
#endif
		{
			WinIndx = kMagStateNormal;
		}

		if (! HavePositionWins[WinIndx]) {
			WinPositionWins[WinIndx].h = leftPos;
			WinPositionWins[WinIndx].v = topPos;
			HavePositionWins[WinIndx] = trueblnr;
			NewWinRect = MainScrnBounds;
		} else {
			SetRect(&NewWinRect, 0, 0, NewWindowWidth, NewWindowHeight);
			OffsetRect(&NewWinRect,
				WinPositionWins[WinIndx].h, WinPositionWins[WinIndx].v);
		}
	}
#endif

#if MayNotFullScreen
	CurWinIndx = WinIndx;
#endif

#if VarFullScreen
	if (UseFullScreen)
#endif
#if MayFullScreen
	{
		hOffset = MainScrnBounds.left - AllScrnBounds.left;
		vOffset = MainScrnBounds.top - AllScrnBounds.top;
	}
#endif

	if (MyCreateNewWindow(&NewWinRect, &gMyMainWindow)) {
		ShowWindow(gMyMainWindow);

		/* check if window rect valid */
#if VarFullScreen
		if (! UseFullScreen)
#endif
#if MayNotFullScreen
		{
			Rect tr;

			if (MyGetWindowTitleBounds(gMyMainWindow, &tr)) {
				if (! RectInRgn(&tr, My_GetGrayRgn())) {
					MySetMacWindContRect(gMyMainWindow,
						&MainScrnBounds);
					if (MyGetWindowTitleBounds(gMyMainWindow, &tr)) {
						if (! RectInRgn(&tr, My_GetGrayRgn())) {
							OffsetRect(&MainScrnBounds,
								0, AllScrnBounds.top - tr.top);
							MySetMacWindContRect(gMyMainWindow,
								&MainScrnBounds);
						}
					}
				}
			}
		}
#endif

#if EnableDragDrop
		if (HaveDragMgrAvail()) {
			(void) PrepareForDragging();
		}
#endif

		IsOk = trueblnr;
	}

	return IsOk;
}

struct MyWState {
	WindowPtr f_MainWindow;
#if MayFullScreen
	short f_hOffset;
	short f_vOffset;
	ui4r f_ViewHSize;
	ui4r f_ViewVSize;
	ui4r f_ViewHStart;
	ui4r f_ViewVStart;
#endif
#if VarFullScreen
	blnr f_UseFullScreen;
#endif
#if EnableMagnify
	blnr f_UseMagnify;
#endif
#if MayNotFullScreen
	int f_CurWinIndx;
#endif
	DragTrackingHandlerUPP f_gGlobalTrackingHandler;
	DragReceiveHandlerUPP f_gGlobalReceiveHandler;
};
typedef struct MyWState MyWState;

LOCALPROC GetMyWState(MyWState *r)
{
	r->f_MainWindow = gMyMainWindow;
#if MayFullScreen
	r->f_hOffset = hOffset;
	r->f_vOffset = vOffset;
	r->f_ViewHSize = ViewHSize;
	r->f_ViewVSize = ViewVSize;
	r->f_ViewHStart = ViewHStart;
	r->f_ViewVStart = ViewVStart;
#endif
#if VarFullScreen
	r->f_UseFullScreen = UseFullScreen;
#endif
#if EnableMagnify
	r->f_UseMagnify = UseMagnify;
#endif
#if MayNotFullScreen
	r->f_CurWinIndx = CurWinIndx;
#endif
	r->f_gGlobalTrackingHandler = gGlobalTrackingHandler;
	r->f_gGlobalReceiveHandler = gGlobalReceiveHandler;
}

LOCALPROC SetMyWState(MyWState *r)
{
	gMyMainWindow = r->f_MainWindow;
#if MayFullScreen
	hOffset = r->f_hOffset;
	vOffset = r->f_vOffset;
	ViewHSize = r->f_ViewHSize;
	ViewVSize = r->f_ViewVSize;
	ViewHStart = r->f_ViewHStart;
	ViewVStart = r->f_ViewVStart;
#endif
#if VarFullScreen
	UseFullScreen = r->f_UseFullScreen;
#endif
#if EnableMagnify
	UseMagnify = r->f_UseMagnify;
#endif
#if MayNotFullScreen
	CurWinIndx = r->f_CurWinIndx;
#endif
	gGlobalTrackingHandler = r->f_gGlobalTrackingHandler;
	gGlobalReceiveHandler = r->f_gGlobalReceiveHandler;
}

LOCALFUNC blnr ReCreateMainWindow(void)
{
	/*
		Like CreateMainWindow (which it calls), except may be
		called when already have window, without CloseMainWindow
		being called first. (Usually with different
		values of WantMagnify and WantFullScreen than
		on the previous call.)

		If there is existing window, and fail to create
		the new one, then existing window must be left alone,
		in valid state. (and return falseblnr. otherwise,
		if succeed, return trueblnr)

		i.e. can allocate the new one before disposing
		of the old one.
	*/
	MyWState old_state;
	MyWState new_state;

#if VarFullScreen
	if (! UseFullScreen)
#endif
#if MayNotFullScreen
	{
		/* save old position */
		if (gMyMainWindow != NULL) {
			Rect r;

			if (MyGetWindowContBounds(gMyMainWindow, &r)) {
				WinPositionWins[CurWinIndx].h = r.left;
				WinPositionWins[CurWinIndx].v = r.top;
			}
		}
	}
#endif

#if MayFullScreen
	UngrabMachine();
#endif

	GetMyWState(&old_state);

	ZapMyWState();

#if VarFullScreen
	UseFullScreen = WantFullScreen;
#endif
#if EnableMagnify
	UseMagnify = WantMagnify;
#endif

	ColorTransValid = falseblnr;

	if (! CreateMainWindow()) {
		CloseMainWindow();
		SetMyWState(&old_state);

#if VarFullScreen
		if (UseFullScreen) {
			My_HideMenuBar();
		} else {
			My_ShowMenuBar();
		}
#endif

		/* avoid retry */
#if VarFullScreen
		WantFullScreen = UseFullScreen;
#endif
#if EnableMagnify
		WantMagnify = UseMagnify;
#endif

		return falseblnr;
	} else {
		GetMyWState(&new_state);
		SetMyWState(&old_state);
		CloseMainWindow();
		SetMyWState(&new_state);

		if (HaveCursorHidden) {
			(void) MyMoveMouse(CurMouseH, CurMouseV);
			WantCursorHidden = trueblnr;
		}

		return trueblnr;
	}
}

#if VarFullScreen && EnableMagnify
enum {
	kWinStateWindowed,
#if EnableMagnify
	kWinStateFullScreen,
#endif
	kNumWinStates
};
#endif

#if VarFullScreen && EnableMagnify
LOCALVAR int WinMagStates[kNumWinStates];
#endif

LOCALPROC ZapWinStateVars(void)
{
#if MayNotFullScreen
	{
		int i;

		for (i = 0; i < kNumMagStates; ++i) {
			HavePositionWins[i] = falseblnr;
		}
	}
#endif
#if VarFullScreen && EnableMagnify
	{
		int i;

		for (i = 0; i < kNumWinStates; ++i) {
			WinMagStates[i] = kMagStateAuto;
		}
	}
#endif
}

#if VarFullScreen
LOCALPROC ToggleWantFullScreen(void)
{
	WantFullScreen = ! WantFullScreen;

#if EnableMagnify
	{
		int OldWinState =
			UseFullScreen ? kWinStateFullScreen : kWinStateWindowed;
		int OldMagState =
			UseMagnify ? kMagStateMagnifgy : kMagStateNormal;
		int NewWinState =
			WantFullScreen ? kWinStateFullScreen : kWinStateWindowed;
		int NewMagState = WinMagStates[NewWinState];

		WinMagStates[OldWinState] = OldMagState;
		if (kMagStateAuto != NewMagState) {
			WantMagnify = (kMagStateMagnifgy == NewMagState);
		} else {
			WantMagnify = falseblnr;
			if (WantFullScreen) {
				Rect r;

				MyGetScreenBitsBounds(&r);
				if (((r.right - r.left)
					>= vMacScreenWidth * MyWindowScale)
					&& ((r.bottom - r.top)
					>= vMacScreenHeight * MyWindowScale)
					)
				{
					WantMagnify = trueblnr;
				}
			}
		}
	}
#endif
}
#endif

LOCALPROC LeaveBackground(void)
{
#if HogCPU
	NoEventsCounter = 0;
#endif

	SetCursorArrow();
	ReconnectKeyCodes3();
}

LOCALPROC EnterBackground(void)
{
	DisconnectKeyCodes3();

#if VarFullScreen
	if (WantFullScreen) {
		ToggleWantFullScreen();
	}
#endif
}

LOCALPROC LeaveSpeedStopped(void)
{
#if MySoundEnabled
	MySound_Start();
#endif

	StartUpTimeAdjust();
}

LOCALPROC EnterSpeedStopped(void)
{
#if MySoundEnabled
	MySound_Stop();
#endif
}

LOCALPROC CheckForSavedTasks(void)
{
	if (MyEvtQNeedRecover) {
		MyEvtQNeedRecover = falseblnr;

		/* attempt cleanup, MyEvtQNeedRecover may get set again */
		MyEvtQTryRecoverFromFull();
	}

#if EnableFSMouseMotion
	if (HaveMouseMotion) {
		MyMouseConstrain();
	}
#endif

	if (RequestMacOff) {
		RequestMacOff = falseblnr;
		if (AnyDiskInserted()) {
			MacMsgOverride(kStrQuitWarningTitle,
				kStrQuitWarningMessage);
		} else {
			ForceMacOff = trueblnr;
		}
	}

	if (ForceMacOff) {
		return;
	}

	if (gTrueBackgroundFlag != gBackgroundFlag) {
		gBackgroundFlag = gTrueBackgroundFlag;
		if (gTrueBackgroundFlag) {
			EnterBackground();
		} else {
			LeaveBackground();
		}
	}

	if (CurSpeedStopped != (SpeedStopped ||
		(gBackgroundFlag && ! RunInBackground
#if EnableAutoSlow && 0
			&& (QuietSubTicks >= 4092)
#endif
		)))
	{
		CurSpeedStopped = ! CurSpeedStopped;
		if (CurSpeedStopped) {
			EnterSpeedStopped();
		} else {
			LeaveSpeedStopped();
		}
	}

#if EnableRecreateW
	if (! (gTrueBackgroundFlag)) {
		if (0
#if EnableMagnify
			|| (UseMagnify != WantMagnify)
#endif
#if VarFullScreen
			|| (UseFullScreen != WantFullScreen)
#endif
			)
		{
			(void) ReCreateMainWindow();
#if HogCPU
			NoEventsCounter = 0;
#endif
		}
	}
#endif

#if MayFullScreen
	if (GrabMachine != (
#if VarFullScreen
		UseFullScreen &&
#endif
		! (gTrueBackgroundFlag || CurSpeedStopped)))
	{
		GrabMachine = ! GrabMachine;
		AdjustMachineGrab();
	}
#endif

	if ((nullpr != SavedBriefMsg) & ! MacMsgDisplayed) {
		MacMsgDisplayOn();
	}

	if (NeedWholeScreenDraw) {
		NeedWholeScreenDraw = falseblnr;
		ScreenChangedAll();
	}

	if (gTrueBackgroundFlag) {
		/*
			dialog during drag and drop hangs if in background
				and don't want recursive dialogs
			so wait til later to display dialog
		*/
	} else {
#if IncludeSonyNew
		if (vSonyNewDiskWanted) {
#if IncludeSonyNameNew
			if (vSonyNewDiskName != NotAPbuf) {
				MakeNewDisk(vSonyNewDiskSize,
					PbufDat[vSonyNewDiskName]);
				PbufDispose(vSonyNewDiskName);
				vSonyNewDiskName = NotAPbuf;
			} else
#endif
			{
				MakeNewDisk(vSonyNewDiskSize, NULL);
			}
			vSonyNewDiskWanted = falseblnr;
				/* must be done after may have gotten disk */
		}
#endif
		if (RequestInsertDisk) {
			RequestInsertDisk = falseblnr;
			InsertADisk0();
		}
	}

#if NeedRequestIthDisk
	if (0 != RequestIthDisk) {
		Sony_InsertIth(RequestIthDisk);
		RequestIthDisk = 0;
	}
#endif

	if (HaveCursorHidden != (WantCursorHidden
		&& ! (gTrueBackgroundFlag || CurSpeedStopped)))
	{
		HaveCursorHidden = ! HaveCursorHidden;
		if (HaveCursorHidden) {
			HideCursor();
		} else {
			ShowCursor();
		}
	}
}

GLOBALOSGLUFUNC blnr ExtraTimeNotOver(void)
{
	UpdateTrueEmulatedTime();
	return TrueEmulatedTime == OnTrueTime;
}

#define CheckItem CheckMenuItem

/* Menu Constants */

#define kAppleMenu   128
#define kFileMenu    129
#define kSpecialMenu 130

/* Apple */

enum {
	kAppleNull,

	kAppleAboutItem,
	kAppleSep1,

	kNumAppleItems
};

/* File */

enum {
	kFileNull,

	kFileOpenDiskImage,
	kFileSep1,
	kFileQuitItem,

	kNumFileItems
};

/* Special */

enum {
	kSpecialNull,

	kSpecialMoreCommandsItem,

	kNumSpecialItems
};

LOCALPROC DoOpenDA(short menuItem)
{
	Str32 name;
	GrafPtr savePort;

	GetPort(&savePort);
	GetMenuItemText(GetMenuHandle(kAppleMenu), menuItem, name);
	OpenDeskAcc(name);
	SystemTask();
	SetPort(savePort);
}

LOCALPROC MacOS_HandleMenu(short menuID, short menuItem)
{
	switch (menuID) {
		case kAppleMenu:
			if (kAppleAboutItem == menuItem) {
				DoAboutMsg();
			} else {
				DoOpenDA(menuItem);
			}
			break;

		case kFileMenu:
			switch (menuItem) {
				case kFileOpenDiskImage:
					RequestInsertDisk = trueblnr;
					break;

				case kFileQuitItem:
					RequestMacOff = trueblnr;
					break;
			}
			break;

		case kSpecialMenu:
			switch (menuItem) {
				case kSpecialMoreCommandsItem:
					DoMoreCommandsMsg();
					break;
			}
			break;

		default:
			/* if 0 == menuID, then no command chosen from menu */
			/* do nothing */
			break;
	}
}

LOCALPROC HandleMacEvent(EventRecord *theEvent)
{
	WindowPtr whichWindow;
	GrafPtr savePort;

	switch(theEvent->what) {
		case mouseDown:
			switch (FindWindow(theEvent->where, &whichWindow)) {
				case inSysWindow:
					SystemClick(theEvent, whichWindow);
					break;
				case inMenuBar:
					ForceShowCursor();
					{
						long menuSelection =
							MenuSelect(theEvent->where);
						MacOS_HandleMenu(HiWord(menuSelection),
							LoWord(menuSelection));
					}
					HiliteMenu(0);
					break;

				case inDrag:
					{
						Rect r;

						MyGetScreenBitsBounds(&r);
						DragWindow(whichWindow, theEvent->where, &r);
					}
					break;

				case inContent:
					if (FrontWindow() != whichWindow) {
						SelectWindow(whichWindow);
					}
					if (whichWindow == gMyMainWindow) {
						MousePositionNotifyFromGlobal(theEvent->where);
						MyMouseButtonSet(trueblnr);
					}
					break;

				case inGoAway:
					if (TrackGoAway(whichWindow, theEvent->where)) {
						RequestMacOff = trueblnr;
					}
					break;

				case inZoomIn:
				case inZoomOut:
					/* Zoom Boxes */
					break;
			}
			break;
		case mouseUp:
			MousePositionNotifyFromGlobal(theEvent->where);
			MyMouseButtonSet(falseblnr);
			break;

		case updateEvt:
			GetPort(&savePort);
			BeginUpdate((WindowPtr) theEvent->message);

			if ((WindowPtr)theEvent->message == gMyMainWindow) {
				Update_Screen();
			}

			EndUpdate((WindowPtr) theEvent->message);
			SetPort(savePort);
			break;

		case keyDown:
		case autoKey:
		case keyUp:
			/* ignore it */
			break;
		case osEvt:
			if ((theEvent->message >> 24) & suspendResumeMessage) {
				if (theEvent->message & 1) {
					gTrueBackgroundFlag = falseblnr;
				} else {
					gTrueBackgroundFlag = trueblnr;
				}
			}
			break;
		case kHighLevelEvent:
			if (kCoreEventClass == (AEEventClass)theEvent->message) {
				if (/* CheckSysCode */ noErr ==
					(AEProcessAppleEvent(theEvent)))
				{
				}
			} else {
				/* vCheckSysCode(errAENotAppleEvent); */
			}
			break;
	}
}

LOCALPROC WaitForTheNextEvent(void)
{
	/*
		Wait for the next event
		from the operating system, we have nothing better
		to do. Call HandleTheEvent and return (only
		wait for one event).
	*/

	EventRecord theEvent;

	if (
#if HaveCPUfamM68K
		(! HaveWaitNextEventAvail()) ?
		GetNextEvent(everyEvent, &theEvent) :
#endif
		WaitNextEvent(everyEvent, &theEvent,
			(gTrueBackgroundFlag && ! RunInBackground)
				? 5 * 60 * 60
				: 5,
				/*
					still need to check for
					control key when SpeedStopped,
					don't get event
				*/
			NULL))
	{
		HandleMacEvent(&theEvent);
	}
}

LOCALPROC DontWaitForEvent(void)
{
	/* we're busy, but see what system wants */

	EventRecord theEvent;
	int i = 0;

#if 0 /* this seems to cause crashes on some machines */
	if (EventAvail(everyEvent, &theEvent)) {
		NoEventsCounter = 0;
#endif

		while ((
#if HaveCPUfamM68K
			(! HaveWaitNextEventAvail()) ?
			GetNextEvent(everyEvent, &theEvent) :
#endif
			WaitNextEvent(everyEvent, &theEvent, 0, NULL))
			&& (i < 10))
		{
			HandleMacEvent(&theEvent);
#if HogCPU
			NoEventsCounter = 0;
#endif
			++i;
		}
#if 0
	}
#endif
}

#define PrivateEventMask \
	(mDownMask | mUpMask | keyDownMask | keyUpMask | autoKeyMask)

#define IsPowOf2(x) (0 == ((x) & ((x) - 1)))

LOCALPROC CheckForSystemEvents(void)
{
	/*
		Handle any events that are waiting for us.
		Return immediately when no more events
		are waiting, don't wait for more.
	*/

#if HogCPU && MayFullScreen
	/*
		only hog cpu in full screen mode
	*/
	if (
#if VarFullScreen
		UseFullScreen &&
#endif
		((ui3b) -1 == SpeedValue) && ! CurSpeedStopped)
	{
		EventRecord theEvent;

		if (! OSEventAvail(everyEvent, &theEvent)) {
			/*
				if no OSEvent now, and not looking for aftermath of
				event, assume there is no event of any kind we need
				to look at
			*/
			if (NoEventsCounter < 256) {
				++NoEventsCounter;
				if (IsPowOf2(NoEventsCounter)) {
					DontWaitForEvent();
				}
			}
		} else {
			WindowPtr whichWindow;

			blnr PrivateEvent = falseblnr;
			switch (theEvent.what) {
				case keyDown:
				case autoKey:
				case keyUp:
				case mouseUp:
					PrivateEvent = trueblnr;
					break;
				case mouseDown:
					if ((inContent ==
							FindWindow(theEvent.where, &whichWindow))
						&& (whichWindow == gMyMainWindow)
						&& (FrontWindow() == whichWindow))
					{
						PrivateEvent = trueblnr;
					}
					break;
			}
			if (PrivateEvent) {
				/*
					if event can effect only us, and not looking out
					for aftermath of another event, then hog the cpu
				*/
				if (GetOSEvent(PrivateEventMask, &theEvent)) {
					HandleMacEvent(&theEvent);
				}
			} else {
				NoEventsCounter = 0;
				/*
					Have an Event, so reset NoEventsCounter, no matter
					what. WaitNextEvent can return false, even if it did
					handle an event. Such as a click in the collapse
					box. In this case we need to look out for update
					events.
				*/
				DontWaitForEvent();
			}
		}
	} else
#endif
	{
		DontWaitForEvent();
	}

	if (! gBackgroundFlag) {
		CheckKeyBoardState();
	}
}

GLOBALOSGLUPROC WaitForNextTick(void)
{
label_retry:
	CheckForSystemEvents();
	CheckForSavedTasks();
	if (ForceMacOff) {
		return;
	}

	if (CurSpeedStopped) {
		DoneWithDrawingForTick();
		WaitForTheNextEvent();
		goto label_retry;
	}

	/*
		Wait until the end of the current
		tick, then emulate the next tick.
	*/

	if (ExtraTimeNotOver()) {
#if HaveCPUfamM68K
		if (HaveWaitNextEventAvail())
#endif
		{
			EventRecord theEvent;

			if (WaitNextEvent(everyEvent, &theEvent, 1, NULL)) {
				HandleMacEvent(&theEvent);
#if HogCPU
				NoEventsCounter = 0;
#endif
			}
		}
		goto label_retry;
	}

	if (CheckDateTime()) {
#if MySoundEnabled
		MySound_SecondNotify();
#endif
#if EnableDemoMsg
		DemoModeSecondNotify();
#endif
	}

	if (! (gBackgroundFlag)) {
		CheckMouseState();
	}

	OnTrueTime = TrueEmulatedTime;

#if dbglog_TimeStuff
	dbglog_writelnNum("WaitForNextTick, OnTrueTime", OnTrueTime);
#endif
}

#include "PROGMAIN.h"

LOCALPROC AppendMenuCStr(MenuHandle menu, char *s)
{
	Str255 t;

	PStrFromCStr(t, s);
	AppendMenu(menu, t);
}

LOCALPROC AppendMenuConvertCStr(MenuHandle menu,
	char *s, blnr WantEllipsis)
{
	Str255 t;

	NativeStrFromCStr(t, s, WantEllipsis);
	AppendMenu(menu, t);
}

LOCALPROC AppendMenuSep(MenuHandle menu)
{
	AppendMenuCStr(menu, "(-");
}

LOCALFUNC MenuHandle NewMenuFromConvertCStr(short menuID, char *s)
{
	Str255 r;

	NativeStrFromCStr(r, s, falseblnr);
	return NewMenu(menuID, r);
}

LOCALFUNC blnr InstallOurMenus(void)
{
	MenuHandle menu;
	Str255 s;

	PStrFromChar(s, (char)20);
	menu = NewMenu(kAppleMenu, s);
	if (menu != NULL) {
		AppendMenuConvertCStr(menu,
			kStrMenuItemAbout, trueblnr);
		AppendMenuSep(menu);
		AppendResMenu(menu, 'DRVR');
		InsertMenu(menu, 0);
	}

	menu = NewMenuFromConvertCStr(kFileMenu, kStrMenuFile);
	if (menu != NULL) {
		AppendMenuConvertCStr(menu,
			kStrMenuItemOpen, trueblnr);
		{
			AppendMenuSep(menu);
			AppendMenuConvertCStr(menu,
				kStrMenuItemQuit, falseblnr);
		}
		InsertMenu(menu, 0);
	}

	menu = NewMenuFromConvertCStr(kSpecialMenu, kStrMenuSpecial);
	if (menu != NULL) {
		AppendMenuConvertCStr(menu,
			kStrMenuItemMore, trueblnr);
		InsertMenu(menu, 0);
	}

	DrawMenuBar();

	return trueblnr;
}

#if AppearanceAvail
LOCALFUNC blnr InstallOurAppearanceClient(void)
{
	if (HaveAppearanceAvail()) {
		RegisterAppearanceClient();
	}
	return trueblnr;
}
#endif

LOCALFUNC blnr InstallOurEventHandlers(void)
{
	InitKeyCodes();

	if (HaveAppleEvtMgrAvail()) {
		InstallAppleEventHandlers();
	}
	return trueblnr;
}

LOCALPROC ZapOSGLUVars(void)
{
	/*
		Set initial values of variables for
		platform dependent code, where not
		done using c initializers. (such
		as for arrays.)
	*/

	ZapEmKeys();
	InitDrives();
	ZapWinStateVars();
}

LOCALPROC ReserveAllocAll(void)
{
	/* !! must match ChooseTotMemSize in build system !! */

#if dbglog_HAVE
	dbglog_ReserveAlloc();
#endif
	ReserveAllocOneBlock(&ROM, kROM_Size, 5, falseblnr);
	ReserveAllocOneBlock(&screencomparebuff,
		vMacScreenNumBytes, 5, trueblnr);
#if UseControlKeys
	ReserveAllocOneBlock(&CntrlDisplayBuff,
		vMacScreenNumBytes, 5, falseblnr);
#endif
#if EnableMagnify
	ReserveAllocOneBlock(&ScalingBuff,
		vMacScreenNumBytes * (ScaleBuffSzMult), 5, falseblnr);
	ReserveAllocOneBlock(&ScalingTabl,
		ScalingTablsz, 5, falseblnr);
#endif
#if MySoundEnabled
	ReserveAllocOneBlock((ui3p *)&TheSoundBuffer,
		dbhBufferSize, 5, falseblnr);
#endif

	EmulationReserveAlloc();
}

LOCALFUNC blnr AllocMyMemory(void)
{
	uimr n;
	blnr IsOk = falseblnr;

	ReserveAllocOffset = 0;
	ReserveAllocBigBlock = nullpr;
	ReserveAllocAll();
	n = ReserveAllocOffset;
	ReserveAllocBigBlock = (ui3p)NewPtr(n);
	if (NULL == ReserveAllocBigBlock) {
		MacMsg(kStrOutOfMemTitle, kStrOutOfMemMessage, trueblnr);
	} else {
		ReserveAllocOffset = 0;
		ReserveAllocAll();
		if (n != ReserveAllocOffset) {
			/* oops, program error */
		} else {
			IsOk = trueblnr;
		}
	}

	return IsOk;
}

LOCALFUNC blnr InitOSGLU(void)
{
	/*
		run all the initializations
		needed for the program.
	*/

	if (InitMacManagers())
	if (AllocMyMemory())
	if (InitMyApplInfo())
#if dbglog_HAVE
	if (dbglog_open())
#endif
#if AppearanceAvail
	if (InstallOurAppearanceClient())
#endif
	if (InstallOurEventHandlers())
	if (InstallOurMenus())
#if MySoundEnabled
	if (MySound_Init())
#endif
	if (ReCreateMainWindow())
	if (LoadMacRom())
	if (LoadInitialImages())
#if UseActvCode
	if (ActvCodeInit())
#endif
	if (InitLocationDat())
	if (WaitForRom())
	{
		return trueblnr;
	}
	return falseblnr;
}

LOCALPROC UnInitOSGLU(void)
{
	/*
		Do all clean ups needed
		before the program quits.
	*/

	if (MacMsgDisplayed) {
		MacMsgDisplayOff();
	}

#if MayFullScreen
	UngrabMachine();
#endif

#if MySoundEnabled
	MySound_Stop();
#endif

	CloseMainWindow();

#if MayFullScreen
	My_ShowMenuBar();
#endif

#if IncludePbufs
	UnInitPbufs();
#endif
	UnInitDrives();

#if dbglog_HAVE
	dbglog_close();
#endif

	ForceShowCursor();

	if (! gTrueBackgroundFlag) {
		CheckSavedMacMsg();
	}
}

#ifndef MainReturnsInt
#define MainReturnsInt 0
#endif

#ifndef NeedLongGlue
#define NeedLongGlue 0
#endif

#if NeedLongGlue
#define main long_main
#endif

#if MainReturnsInt
int
#else
void
#endif
main(void)
{
	ZapOSGLUVars();
	if (InitOSGLU()) {
		ProgramMain();
	}
	UnInitOSGLU();

#if MainReturnsInt
	return 0;
#endif
}