/* 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 "UI/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 bool LowToolTrapAvailable(short trap_num) { #if DebugTrapAvailableChecks if ((trap_num & 0x0800) == 0) { DebugStr("\pOSTrap in LowToolTrapAvailable"); return false; } if ((trap_num & 0x07ff) >= 0x200) { DebugStr("\pHiToolTrap in LowToolTrapAvailable"); return false; } #endif return GetToolTrapAddress(trap_num) != GetToolTrapAddress(_Unimplemented); } LOCALFUNC bool HiToolTrapAvailable(short trap_num) { #if DebugTrapAvailableChecks if ((trap_num & 0x0800) == 0) { DebugStr("\pOSTrap in HiToolTrapAvailable"); return false; } if (((trap_num & 0x07ff) < 0x200) || ((trap_num & 0x07ff) >= 0x400)) { DebugStr("\pLowToolTrap in HiToolTrapAvailable"); return false; } #endif if (GetToolTrapAddress(_InitGraf) == GetToolTrapAddress(0xAA6E)) { return false; } else { return GetToolTrapAddress(trap_num) != GetToolTrapAddress(_Unimplemented); } } LOCALFUNC bool OSTrapAvailable(short trap_num) { #if DebugTrapAvailableChecks if ((trap_num & 0x0800) != 0) { DebugStr("\pToolTrap in ToolTrapAvailable"); return false; } #endif return GetOSTrapAddress(trap_num) != GetToolTrapAddress(_Unimplemented); } LOCALVAR bool EnvrAttrWaitNextEventAvail; LOCALVAR bool HaveEnvrAttrWaitNextEventAvail = false; LOCALFUNC bool HaveWaitNextEventAvail(void) { if (! HaveEnvrAttrWaitNextEventAvail) { EnvrAttrWaitNextEventAvail = LowToolTrapAvailable(_WaitNextEvent); HaveEnvrAttrWaitNextEventAvail = true; } return EnvrAttrWaitNextEventAvail; } LOCALVAR bool EnvrAttrGestaltAvail; LOCALVAR bool HaveEnvrAttrGestaltAvail = false; LOCALFUNC bool HaveGestaltAvail(void) { if (! HaveEnvrAttrGestaltAvail) { EnvrAttrGestaltAvail = (! 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 = true; } return EnvrAttrGestaltAvail; } #else /* for PowerPC, assume always have these routines */ #define HaveWaitNextEventAvail() true #define HaveGestaltAvail() true #endif LOCALVAR bool EnvrAttrAliasMgrAvail; LOCALVAR bool HaveEnvrAttrAliasMgrAvail = false; LOCALFUNC bool HaveAliasMgrAvail(void) { if (! HaveEnvrAttrAliasMgrAvail) { long reply; EnvrAttrAliasMgrAvail = HaveGestaltAvail() && (noErr == Gestalt(gestaltAliasMgrAttr, &reply)) && TestBit(reply, gestaltAliasMgrPresent); HaveEnvrAttrAliasMgrAvail = true; } return EnvrAttrAliasMgrAvail; } LOCALVAR bool EnvrAttrAppleEvtMgrAvail; LOCALVAR bool HaveEnvrAttrAppleEvtMgrAvail = false; LOCALFUNC bool HaveAppleEvtMgrAvail(void) { if (! HaveEnvrAttrAppleEvtMgrAvail) { long reply; EnvrAttrAppleEvtMgrAvail = HaveGestaltAvail() && (noErr == Gestalt(gestaltAppleEventsAttr, &reply)) && TestBit(reply, gestaltAppleEventsPresent); HaveEnvrAttrAppleEvtMgrAvail = true; } return EnvrAttrAppleEvtMgrAvail; } #if EnableDragDrop LOCALVAR bool EnvrAttrDragMgrAvail; LOCALVAR bool HaveEnvrAttrDragMgrAvail = false; LOCALFUNC bool HaveDragMgrAvail(void) { if (! HaveEnvrAttrDragMgrAvail) { long reply; EnvrAttrDragMgrAvail = HaveGestaltAvail() && (noErr == Gestalt(gestaltDragMgrAttr, &reply)) && TestBit(reply, gestaltDragMgrPresent); HaveEnvrAttrDragMgrAvail = true; } return EnvrAttrDragMgrAvail; } #endif #ifndef Windows85APIAvail #define Windows85APIAvail 1 #endif #if Windows85APIAvail LOCALVAR bool EnvrAttrHideShowMenuAvail; LOCALVAR bool HaveEnvrAttrHideShowMenuAvail = false; LOCALFUNC bool HaveHideShowMenuAvail(void) { if (! HaveEnvrAttrHideShowMenuAvail) { long reply; EnvrAttrHideShowMenuAvail = HaveGestaltAvail() && (noErr == Gestalt(gestaltMenuMgrAttr, &reply)); HaveEnvrAttrHideShowMenuAvail = true; } return EnvrAttrHideShowMenuAvail; } #endif #if AppearanceAvail LOCALVAR bool EnvrAttrAppearanceAvail; LOCALVAR bool HaveEnvrAttrAppearanceAvail = false; LOCALFUNC bool HaveAppearanceAvail(void) { if (! HaveEnvrAttrAppearanceAvail) { long reply; EnvrAttrAppearanceAvail = HaveGestaltAvail() && (noErr == Gestalt(gestaltAppearanceAttr, &reply)); HaveEnvrAttrAppearanceAvail = true; } return EnvrAttrAppearanceAvail; } #endif #if HaveCPUfamM68K LOCALVAR bool EnvrAttrSndMngrAvail; LOCALVAR bool HaveEnvrAttrSndMngrAvail = false; LOCALFUNC bool HaveSndMngrAvail(void) { if (! HaveEnvrAttrSndMngrAvail) { EnvrAttrSndMngrAvail = LowToolTrapAvailable(_SndNewChannel); HaveEnvrAttrSndMngrAvail = true; } return EnvrAttrSndMngrAvail; } #endif #if NavigationAvail LOCALVAR bool EnvrAttrNavServicesAvail; LOCALVAR bool HaveEnvrAttrNavServicesAvail = false; LOCALFUNC bool HaveNavServicesAvail(void) { if (! HaveEnvrAttrNavServicesAvail) { EnvrAttrNavServicesAvail = NavServicesAvailable(); HaveEnvrAttrNavServicesAvail = true; } return EnvrAttrNavServicesAvail; } #endif #if HaveCPUfamM68K LOCALVAR bool EnvrAttrFSSpecCallsAvail; LOCALVAR bool HaveEnvrAttrFSSpecCallsAvail = false; LOCALFUNC bool HaveFSSpecCallsAvail(void) { if (! HaveEnvrAttrFSSpecCallsAvail) { long reply; EnvrAttrFSSpecCallsAvail = HaveGestaltAvail() && (noErr == Gestalt(gestaltFSAttr, &reply)) && TestBit(reply, gestaltHasFSSpecCalls); HaveEnvrAttrFSSpecCallsAvail = true; } return EnvrAttrFSSpecCallsAvail; } #endif #if Windows85APIAvail LOCALVAR bool EnvrAttrNewWndMgrAvail; LOCALVAR bool HaveEnvrAttrNewWndMgrAvail = false; LOCALFUNC bool HaveNewWndMgrAvail(void) { if (! HaveEnvrAttrNewWndMgrAvail) { long reply; EnvrAttrNewWndMgrAvail = HaveGestaltAvail() && (noErr == Gestalt(gestaltWindowMgrAttr, &reply)) && TestBit(reply, gestaltWindowMgrPresentBit); HaveEnvrAttrNewWndMgrAvail = true; } return EnvrAttrNewWndMgrAvail; } #endif /* --- initial initialization --- */ #if defined(__SC__) || ((defined(powerc) || defined(__powerc)) \ && ! defined(__MWERKS__)) /* GLOBALVAR */ QDGlobals qd; #endif LOCALFUNC bool InitMacManagers(void) { MaxApplZone(); { int i; for (i = 7; --i >= 0; ) { MoreMasters(); } } InitGraf(&qd.thePort); InitFonts(); InitWindows(); InitMenus(); TEInit(); InitDialogs(NULL); InitCursor(); return true; } /* --- 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)(uint16_t)(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 Dir_R { long DirId; short VRefNum; }; typedef struct Dir_R Dir_R; LOCALFUNC tMacErr OpenNamedFileInFolder(Dir_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, true, &isFolder, &isAlias))) if (CheckSaveMacErr( FSpOpenDF(&spec, fsRdPerm, refnum))) { } } return err; } /* --- sending debugging info to file --- */ #if dbglog_HAVE #define Support64kROM 0 #define tErr tMacErr typedef unsigned char * Ptr; LOCALFUNC tErr HGetDir_v2(Dir_R *d) { tErr 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 tErr WriteBytes_v2(short refNum, Ptr 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 tErr CloseFile_v2(short refNum) { ParamBlockRec r; r.ioParam.ioCompletion = NULL; r.ioParam.ioRefNum = refNum; return PBCloseSync(&r); #if 0 return (tErr)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 tErr FileOpen_v2(Dir_R *d, StringPtr s, char Permssn, short *refnum) { tErr 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 tErr FileOpenWrite_v2(Dir_R *d, StringPtr s, short *refnum) { return FileOpen_v2(d, s, (char)fsWrPerm, refnum); } LOCALFUNC tErr DeleteFile_v2(Dir_R *d, StringPtr s) { tErr 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 tErr CreateFile_v2(Dir_R *d, StringPtr s) { tErr 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 tErr FileGetInfo_v2(Dir_R *d, StringPtr s, HParamBlockRec *r) { tErr 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 tErr FileSetInfo_v2(Dir_R *d, StringPtr s, HParamBlockRec *r) { tErr 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 tErr FileSetTypeCreator_v2(Dir_R *d, StringPtr s, OSType creator, OSType fileType) { tErr err; HParamBlockRec r; if (noErr == (err = FileGetInfo_v2(d, s, &r))) { r.fileParam.ioFlFndrInfo.fdType = fileType; r.fileParam.ioFlFndrInfo.fdCreator = creator; err = FileSetInfo_v2(d, s, &r); } return err; } LOCALFUNC tErr CreateFileOverWrite_v2(Dir_R *d, StringPtr s) { tErr err; err = CreateFile_v2(d, s); if (dupFNErr == err) { if (noErr == (err = DeleteFile_v2(d, s))) { err = CreateFile_v2(d, s); } } return err; } LOCALFUNC tErr OpenNewFile_v3(Dir_R *d, StringPtr s, OSType creator, OSType fileType, short *refnum) /* Deletes old file if already exists. */ { tErr err; err = CreateFileOverWrite_v2(d, s); if (noErr == err) { err = FileSetTypeCreator_v2(d, s, creator, fileType); if (noErr == err) { err = FileOpenWrite_v2(d, s, refnum); } if (noErr != err) { (void) DeleteFile_v2(d, s); /* ignore any error, since already got one */ } } return err; } LOCALVAR short dbglog_File = NotAfileRef; LOCALVAR tErr dbglog_err = noErr; LOCALFUNC bool dbglog_open0(void) { tMacErr err; Dir_R d; if (noErr == (err = HGetDir_v2(&d))) { err = FileOpen_v2(&d, (StringPtr)"\pdbglog", (char)fsWrPerm, &dbglog_File); if (mnvm_noErr /* fnfErr */ == err) { err = SetEOF(dbglog_File, 0); } else { err = OpenNewFile_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 = WriteBytes_v2(dbglog_File, (Ptr)s, L); } } LOCALPROC dbglog_close0(void) { if (NotAfileRef != dbglog_File) { (void) CloseFile_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 MoveBytes(anyp srcPtr, anyp destPtr, int32_t byteCount) { BlockMove((Ptr)srcPtr, (Ptr)destPtr, byteCount); } /* don't want to include c libraries, so: */ LOCALFUNC int32_t CStrLen(char *src) { char *p = src; while (*p++ != 0) { } return ((int32_t)p) - ((int32_t)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; MoveBytes((anyp)s, (anyp)r, L); } LOCALPROC PStrFromChar(ps3p r, char x) { r[0] = 1; r[1] = (char)x; } LOCALPROC PStrFromHandle(ps3p r, Handle h, uint32_t MaxL) { uint32_t 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 _LMGetTime #if LowMemAPIAvail #define _LMGetTime LMGetTime #else #define _LMGetTime() (*(SInt32 *)(0x020C)) #endif #endif #ifndef _LMGetMBarHeight #if LowMemAPIAvail #define _LMGetMBarHeight LMGetMBarHeight #else #define _LMGetMBarHeight() (*(short *)(0x0BAA)) #endif #endif #ifndef _GetGrayRgn #if /* LowMemAPIAvail */ 0 #define _GetGrayRgn LMGetGrayRgn #else #define _GetGrayRgn() (*(RgnHandle *)(0x9EE)) #endif #endif #ifndef _LMGetCurApName #if LowMemAPIAvail #define _LMGetCurApName LMGetCurApName #else #define _LMGetCurApName() ((StringPtr) 0x0910) #endif #endif #define GetScreenBitsBounds(r) (*r) = qd.screenBits.bounds #define _GetRegionBounds(region, bounds) *(bounds) = \ (**(region)).rgnBBox #define _GetPortPixMap(p) ((p)->portPixMap) #ifndef _WindowRef #if NewNamesAvail #define _WindowRef WindowRef #else #define _WindowRef WindowPtr #endif #endif #define _SetPortWindowPort(w) SetPort(w) LOCALPROC _InvalWindowRect(_WindowRef mw, Rect *r) { GrafPtr SavePort; GetPort(&SavePort); _SetPortWindowPort(mw); InvalRect(r); SetPort(SavePort); } #define _GetWindowPortBounds(w, r) *(r) = ((w)->portRect) LOCALPROC InvalWholeWindow(_WindowRef mw) { Rect bounds; _GetWindowPortBounds(mw, &bounds); _InvalWindowRect(mw, &bounds); } LOCALPROC SetMacWindContRect(_WindowRef mw, Rect *r) { #if Windows85APIAvail if (HaveNewWndMgrAvail()) { (void) SetWindowBounds (mw, kWindowContentRgn, r); } else #endif { #if MightNotHaveWindows85Avail MoveWindow(mw, r->left, r->top, false); SizeWindow(mw, r->right - r->left, r->bottom - r->top, true); #endif } InvalWholeWindow(mw); } LOCALFUNC bool GetWindowTitleBounds(_WindowRef mw, Rect *r) { #if Windows85APIAvail if (HaveNewWndMgrAvail()) { return (noErr == GetWindowBounds(mw, kWindowTitleBarRgn, r)); } else #endif { #if MightNotHaveWindows85Avail _GetRegionBounds(((WindowPeek)mw)->strucRgn, r); r->bottom = r->top + 15; r->left += 4; r->right -= 4; #endif return true; } } #define topLeft(r) (((Point *) &(r))[0]) #define botRight(r) (((Point *) &(r))[1]) LOCALFUNC bool GetWindowContBounds(_WindowRef mw, Rect *r) { #if Windows85APIAvail if (HaveNewWndMgrAvail()) { return (noErr == GetWindowBounds(mw, kWindowContentRgn, r)); } else #endif { #if MightNotHaveWindows85Avail GrafPtr oldPort; GetPort(&oldPort); _SetPortWindowPort(mw); _GetWindowPortBounds(mw, r); LocalToGlobal(&topLeft(*r)); LocalToGlobal(&botRight(*r)); SetPort(oldPort); #endif return true; } } LOCALPROC GetGrayRgnBounds(Rect *r) { _GetRegionBounds(_GetGrayRgn(), (Rect *)r); } /* --- main window data --- */ LOCALVAR WindowPtr gMainWindow = NULL; #if MayFullScreen LOCALVAR short hOffset; LOCALVAR short vOffset; #endif #if MayFullScreen LOCALVAR bool GrabMachine = false; #endif #if VarFullScreen LOCALVAR bool UseFullScreen = (WantInitFullScreen != 0); #endif #if EnableMagnify LOCALVAR bool UseMagnify = (WantInitMagnify != 0); #endif #if EnableMagnify LOCALPROC ScaleRect(Rect *r) { r->left *= WindowScale; r->right *= WindowScale; r->top *= WindowScale; r->bottom *= WindowScale; } #endif LOCALPROC SetScrnRectFromCoords(Rect *r, int16_t top, int16_t left, int16_t bottom, int16_t 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) { ScaleRect(r); } #endif #if VarFullScreen if (UseFullScreen) #endif #if MayFullScreen { OffsetRect(r, hOffset, vOffset); } #endif } #if EnableMagnify #define ScaledHeight (WindowScale * vMacScreenHeight) #define ScaledWidth (WindowScale * vMacScreenWidth) #endif #if EnableMagnify LOCALVAR uint8_t * ScalingBuff = nullpr; #endif #if EnableMagnify LOCALVAR uint8_t * ScalingTabl = nullpr; #define ScalingTablsz (256 * WindowScale) #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 WindowScale #include "SCRNMAPR.h" #endif #if EnableMagnify LOCALPROC SetUpScalingTabl(void) { uint8_t *p4; int i; int j; int k; uint8_t bitsRemaining; uint8_t t1; uint8_t t2; p4 = ScalingTabl; for (i = 0; i < 256; ++i) { bitsRemaining = 8; t2 = 0; for (j = 8; --j >= 0; ) { t1 = (i >> j) & 1; for (k = WindowScale; --k >= 0; ) { t2 = (t2 << 1) | t1; if (--bitsRemaining == 0) { *p4++ = t2; bitsRemaining = 8; t2 = 0; } } } } } #endif LOCALPROC DefaultDrawScreenBuff(int16_t top, int16_t left, int16_t bottom, int16_t 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 = true; } UpdateScaledBWCopy(top, left, bottom, right); ScaleRect(&SrcRect); ScaleRect(&src.bounds); src.baseAddr = (Ptr)ScalingBuff; src.rowBytes *= WindowScale; } else #endif { src.baseAddr = (Ptr)GetCurDrawBuff(); } SetScrnRectFromCoords(&DstRect, top, left, bottom, right); CopyBits(&src, &gMainWindow->portBits, &SrcRect, &DstRect, srcCopy, NULL); /* FrameRect(&SrcRect); for testing */ } LOCALPROC Update_Screen(void) { GrafPtr savePort; GetPort(&savePort); _SetPortWindowPort(gMainWindow); #if VarFullScreen if (UseFullScreen) #endif #if MayFullScreen { PaintRect(&gMainWindow->portRect); } #endif DefaultDrawScreenBuff(0, 0, vMacScreenHeight, vMacScreenWidth); SetPort(savePort); } LOCALPROC HaveChangedScreenBuff(int16_t top, int16_t left, int16_t bottom, int16_t right) { #if 0 /* experimental code in progress */ if (UseFullScreen) { { PixMapHandle pm= (**GetMainDevice()).gdPMap; /* LockPixels(pm); */ #if EnableMagnify if (! UseMagnify) { #define PixelT uint32_t PixelT *p1 = (PixelT *)GetPixBaseAddr(pm); int i; int j; int k; uint32_t *p0 = (uint32_t *)GetCurDrawBuff(); uint32_t SkipBytes = GetPixRowBytes(pm) - sizeof(PixelT) * vMacScreenWidth; uint32_t 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 uint32_t PixelT *p1 = (PixelT *)GetPixBaseAddr(pm); int i; int j; int k; uint32_t *p0 = (uint32_t *)GetCurDrawBuff(); PixelT *p2; uint32_t t0; PixelT a[2]; p1 += vOffset * ScaledWidth; p1 += (long)WindowScale * (long)ScaledWidth * 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 = ScaledWidth; --j >= 0; ) { *p1++ = *p2++; } } #endif } #endif /* UnlockPixels(pm); */ } } else #endif { GrafPtr savePort; GetPort(&savePort); _SetPortWindowPort(gMainWindow); DefaultDrawScreenBuff(top, left, bottom, right); SetPort(savePort); } } LOCALPROC DrawChangesAndClear(void) { if (ScreenChangedBottom > ScreenChangedTop) { HaveChangedScreenBuff(ScreenChangedTop, ScreenChangedLeft, ScreenChangedBottom, ScreenChangedRight); ScreenClearChanges(); } } GLOBALOSGLUPROC DoneWithDrawingForTick(void) { #if EnableFSMouseMotion if (HaveMouseMotion) { AutoScrollScreen(); } #endif DrawChangesAndClear(); } /* --- keyboard --- */ LOCALVAR uint32_t LastEmKeys[4]; LOCALPROC ZapEmKeys(void) { LastEmKeys[0] = 0; LastEmKeys[1] = 0; LastEmKeys[2] = 0; LastEmKeys[3] = 0; } LOCALPROC CheckKeyBoardState(void) { int i; int j; uint32_t NewKeys[4]; GetKeys(*(KeyMap *)NewKeys); for (j = 0; j < 16; ++j) { uint8_t k1 = ((uint8_t *)NewKeys)[j]; uint8_t k2 = ((uint8_t *)LastEmKeys)[j]; uint8_t 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 = false; #define KeyMap_TestBit(m, key) \ ((((uint8_t *)m)[(key) / 8] & (1 << ((key) & 7))) != 0) LOCALPROC ReconnectKeyCodes3(void) /* so keys already pressed will be ignored */ { int i; int j; bool oldv; bool newv; uint32_t 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 = false; for (i = 0; i < 16; ++i) { uint8_t v = ((uint8_t *)NewKeys)[i]; for (j = 0; j < 8; ++j) { if (0 != ((1 << j) & v)) { uint8_t k = i * 8 + j; if (MKC_CapsLock != k) { Keyboard_UpdateKeyMap2(Keyboard_RemapMac(k), true); } } } } } for (i = 0; i < 4; ++i) { LastEmKeys[i] = NewKeys[i]; } } /* --- cursor hiding --- */ LOCALVAR bool HaveCursorHidden = false; LOCALVAR bool WantCursorHidden = false; LOCALPROC ForceShowCursor(void) { if (HaveCursorHidden) { HaveCursorHidden = false; 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 MoveMouse). */ /* 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 RawMouse 0x082C /* low memory global that has current mouse loc */ #define MTemp 0x0828 /* low memory global that has current mouse loc */ #define CrsrNew 0x08CE /* set after you change mtemp and rawmouse */ #define CrsrCouple 0x08CF /* true if the cursor is tied to the mouse */ LOCALFUNC bool MoveMouse(int16_t h, int16_t v) { /* Move the cursor to the point h, v on the emulated screen. if detect that this fails return false, otherwise return true. (on some platforms it is possible to move the curser, but there is no way to detect failure.) */ GrafPtr oldPort; Point CurMousePos; Point NewMousePos; uint32_t difftime; bool IsOk; long int StartTime = TickCount(); #if VarFullScreen if (UseFullScreen) #endif #if MayFullScreen { h -= ViewHStart; v -= ViewVStart; } #endif #if EnableMagnify if (UseMagnify) { h *= WindowScale; v *= WindowScale; } #endif #if VarFullScreen if (UseFullScreen) #endif #if MayFullScreen { h += hOffset; v += vOffset; } #endif CurMousePos.h = h; CurMousePos.v = v; GetPort(&oldPort); _SetPortWindowPort(gMainWindow); LocalToGlobal(&CurMousePos); do { #if HaveCPUfamM68K if (! HiToolTrapAvailable(_CursorDeviceDispatch)) { *(Point *)RawMouse = CurMousePos; *(Point *)MTemp = CurMousePos; *(Ptr)CrsrNew = *(Ptr)CrsrCouple; #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 = (uint32_t)(TickCount() - StartTime); } while ((! IsOk) && (difftime < 5)); SetPort(oldPort); return IsOk; } #if EnableFSMouseMotion LOCALPROC AdjustMouseMotionGrab(void) { if (gMainWindow != NULL) { #if MayFullScreen if (GrabMachine) { /* if magnification changes, need to reset, even if HaveMouseMotion already true */ if (MoveMouse(ViewHStart + (ViewHSize / 2), ViewVStart + (ViewVSize / 2))) { SavedMouseH = ViewHStart + (ViewHSize / 2); SavedMouseV = ViewVStart + (ViewVSize / 2); HaveMouseMotion = true; } } else #endif { if (HaveMouseMotion) { (void) MoveMouse(CurMouseH, CurMouseV); HaveMouseMotion = false; } } } } #endif #if EnableFSMouseMotion LOCALPROC MouseConstrain(void) { int16_t shiftdh; int16_t 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 (! MoveMouse(SavedMouseH, SavedMouseV)) { HaveMouseMotion = false; } } } #endif LOCALPROC MousePositionNotify(Point NewMousePos) { bool ShouldHaveCursorHidden = true; #if VarFullScreen if (UseFullScreen) #endif #if MayFullScreen { NewMousePos.h -= hOffset; NewMousePos.v -= vOffset; } #endif #if VarFullScreen else #endif #if MayNotFullScreen { if (! PtInRgn(NewMousePos, gMainWindow->visRgn)) { ShouldHaveCursorHidden = false; } } #endif #if EnableMagnify if (UseMagnify) { NewMousePos.h /= WindowScale; NewMousePos.v /= WindowScale; } #endif #if VarFullScreen if (UseFullScreen) #endif #if MayFullScreen { NewMousePos.h += ViewHStart; NewMousePos.v += ViewVStart; } #endif #if EnableFSMouseMotion if (HaveMouseMotion) { MousePositionSetDelta( NewMousePos.h - SavedMouseH, NewMousePos.v - SavedMouseV); SavedMouseH = NewMousePos.h; SavedMouseV = NewMousePos.v; } else #endif { if (NewMousePos.h < 0) { NewMousePos.h = 0; ShouldHaveCursorHidden = false; } else if (NewMousePos.h >= vMacScreenWidth) { NewMousePos.h = vMacScreenWidth - 1; ShouldHaveCursorHidden = false; } if (NewMousePos.v < 0) { NewMousePos.v = 0; ShouldHaveCursorHidden = false; } else if (NewMousePos.v >= vMacScreenHeight) { NewMousePos.v = vMacScreenHeight - 1; ShouldHaveCursorHidden = false; } #if VarFullScreen if (UseFullScreen) #endif #if MayFullScreen { ShouldHaveCursorHidden = true; } #endif /* if (ShouldHaveCursorHidden || CurMouseButton) */ /* for a game like arkanoid, would like mouse to still move even when outside window in one direction */ MousePositionSet(NewMousePos.h, NewMousePos.v); } WantCursorHidden = ShouldHaveCursorHidden; } LOCALPROC MousePositionNotifyFromGlobal(Point NewMousePos) { GrafPtr oldPort; GetPort(&oldPort); _SetPortWindowPort(gMainWindow); GlobalToLocal(&NewMousePos); SetPort(oldPort); MousePositionNotify(NewMousePos); } LOCALPROC CheckMouseState(void) { Point NewMousePos; GrafPtr oldPort; GetPort(&oldPort); _SetPortWindowPort(gMainWindow); GetMouse(&NewMousePos); SetPort(oldPort); MousePositionNotify(NewMousePos); } LOCALPROC DisconnectKeyCodes3(void) { DisconnectKeyCodes2(); MouseButtonSet(false); ForceShowCursor(); } /* --- time, date, location --- */ #define dbglog_TimeStuff (0 && dbglog_HAVE) /* be sure to avoid getting confused if TickCount overflows and wraps. */ LOCALVAR uint32_t 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(); int32_t 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 bool 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. */ uint32_t NewMacDateInSecond; NewMacDateInSecond = _LMGetTime(); if (CurMacDateInSeconds != NewMacDateInSecond) { CurMacDateInSeconds = NewMacDateInSecond; return true; } else { return false; } } LOCALFUNC bool InitLocationDat(void) { #if AutoLocation || AutoTimeZone MachineLocation loc; ReadLocation(&loc); #if AutoLocation CurMacLatitude = (uint32_t)loc.latitude; CurMacLongitude = (uint32_t)loc.longitude; #endif #if AutoTimeZone CurMacDelta = (uint32_t)loc.u.gmtDelta; #endif #endif (void) CheckDateTime(); return true; } /* --- sound --- */ #if SoundEnabled #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 uint16_t ThePlayOffset; volatile static uint16_t TheFillOffset; volatile static uint16_t MinFilledSoundBuffs; #if dbglog_SoundBuffStats LOCALVAR uint16_t MaxFilledSoundBuffs; #endif LOCALVAR uint16_t TheWriteOffset; LOCALPROC Sound_Start0(void) { /* Reset variables */ ThePlayOffset = 0; TheFillOffset = 0; TheWriteOffset = 0; MinFilledSoundBuffs = kSoundBuffers + 1; #if dbglog_SoundBuffStats MaxFilledSoundBuffs = 0; #endif } GLOBALOSGLUFUNC tpSoundSamp Sound_BeginWrite(uint16_t n, uint16_t *actL) { uint16_t ToFillLen = kAllBuffLen - (TheWriteOffset - ThePlayOffset); uint16_t 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 Sound_WroteABlock(void) { #if (4 == kLn2SoundSampSz) uint16_t PrevWriteOffset = TheWriteOffset - kOneBuffLen; tpSoundSamp p = TheSoundBuffer + (PrevWriteOffset & kAllBuffMask); #endif #if dbglog_SoundStuff dbglog_writeln("enter Sound_WroteABlock"); #endif ConvertSoundBlockToNative(p); TheFillOffset = TheWriteOffset; #if dbglog_SoundBuffStats { uint16_t ToPlayLen = TheFillOffset - ThePlayOffset; uint16_t ToPlayBuffs = ToPlayLen >> kLnOneBuffLen; if (ToPlayBuffs > MaxFilledSoundBuffs) { MaxFilledSoundBuffs = ToPlayBuffs; } } #endif } LOCALFUNC bool Sound_EndWrite0(uint16_t actL) { bool v; TheWriteOffset += actL; if (0 != (TheWriteOffset & kOneBuffMask)) { v = false; } else { /* just finished a block */ Sound_WroteABlock(); v = true; } return v; } LOCALPROC Sound_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; uint32_t v = (((uint32_t)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 SoundR { tpSoundSamp fTheSoundBuffer; volatile uint16_t (*fPlayOffset); volatile uint16_t (*fFillOffset); volatile uint16_t (*fMinFilledSoundBuffs); volatile bool PlayingBuffBlock; volatile trSoundSamp lastv; volatile bool wantplaying; volatile bool StartingBlocks; CmpSoundHeader /* ExtSoundHeader */ soundHeader; }; typedef struct SoundR SoundR; /* 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 Sound_CallBack(SndChannelPtr theChannel, SndCommand * theCallBackCmd) { SoundR *datp = (SoundR *)(theCallBackCmd->param2); bool wantplaying0 = datp->wantplaying; trSoundSamp v0 = datp->lastv; #if dbglog_SoundStuff dbglog_writeln("Enter Sound_CallBack"); #endif if (datp->PlayingBuffBlock) { /* finish with last sample */ #if dbglog_SoundStuff dbglog_writeln("done with sample"); #endif *datp->fPlayOffset += kOneBuffLen; datp->PlayingBuffBlock = false; } if ((! wantplaying0) && (kCenterSound == v0)) { #if dbglog_SoundStuff dbglog_writeln("terminating"); #endif } else { SndCommand playCmd; tpSoundSamp p; trSoundSamp v1 = v0; bool WantRamp = false; uint16_t CurPlayOffset = *datp->fPlayOffset; uint16_t ToPlayLen = *datp->fFillOffset - CurPlayOffset; uint16_t FilledSoundBuffs = ToPlayLen >> kLnOneBuffLen; if (FilledSoundBuffs < *datp->fMinFilledSoundBuffs) { *datp->fMinFilledSoundBuffs = FilledSoundBuffs; } if (! wantplaying0) { #if dbglog_SoundStuff dbglog_writeln("playing end transistion"); #endif v1 = kCenterSound; WantRamp = true; } else if (datp->StartingBlocks) { #if dbglog_SoundStuff dbglog_writeln("playing start block"); #endif if ((ToPlayLen >> kLnOneBuffLen) < 12) { datp->StartingBlocks = false; #if dbglog_SoundStuff dbglog_writeln("have enough samples to start"); #endif p = datp->fTheSoundBuffer + (CurPlayOffset & kAllBuffMask); v1 = ConvertSoundSampleFromNative(*p); } WantRamp = true; } else if (0 == FilledSoundBuffs) { #if dbglog_SoundStuff dbglog_writeln("playing under run"); #endif WantRamp = true; } else { /* play next sample */ p = datp->fTheSoundBuffer + (CurPlayOffset & kAllBuffMask); datp->PlayingBuffBlock = true; 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 SoundR cur_audio; LOCALVAR SndCallBackUPP gCarbonSndPlayDoubleBufferCallBackUPP = NULL; LOCALVAR SndChannelPtr sndChannel = NULL; /* our sound channel */ LOCALPROC Sound_Start(void) { if (NULL == sndChannel) #if HaveCPUfamM68K if (HaveSndMngrAvail()) #endif { SndCommand callBack; SndChannelPtr chan = NULL; cur_audio.wantplaying = false; cur_audio.StartingBlocks = false; Sound_Start0(); SndNewChannel(&chan, sampledSynth, initMono, nil); if (NULL != chan) { sndChannel = chan; cur_audio.PlayingBuffBlock = false; cur_audio.lastv = kCenterSound; cur_audio.StartingBlocks = true; cur_audio.wantplaying = true; 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 Sound_Stop(void) { #if dbglog_SoundStuff dbglog_writeln("enter Sound_Stop"); #endif if (NULL != sndChannel) { uint16_t retry_limit = 50; /* half of a second */ SCStatus r; cur_audio.wantplaying = false; #if dbglog_SoundStuff dbglog_writeln("cleared wantplaying"); #endif label_retry: r.scChannelBusy = false; /* 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 Sound_Stop"); #endif } #define SOUND_SAMPLERATE rate22khz /* = 0x56EE8BA3 = (7833600 * 2 / 704) << 16 */ LOCALFUNC bool Sound_Init(void) { #if dbglog_SoundStuff dbglog_writeln("enter Sound_Init"); #endif cur_audio.fTheSoundBuffer = TheSoundBuffer; cur_audio.fPlayOffset = &ThePlayOffset; cur_audio.fFillOffset = &TheFillOffset; cur_audio.fMinFilledSoundBuffs = &MinFilledSoundBuffs; cur_audio.wantplaying = false; /* 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(Sound_CallBack); if (gCarbonSndPlayDoubleBufferCallBackUPP != NULL) { Sound_Start(); /* This should be taken care of by LeaveSpeedStopped, but since takes a while to get going properly, start early. */ return true; } return false; } GLOBALOSGLUPROC Sound_EndWrite(uint16_t actL) { if (Sound_EndWrite0(actL)) { } } LOCALPROC Sound_SecondNotify(void) { if (sndChannel != NULL) { Sound_SecondNotify0(); } } #endif #if MayFullScreen LOCALPROC AdjustMachineGrab(void) { #if EnableFSMouseMotion AdjustMouseMotionGrab(); #endif #if 0 AdjustMainScreenGrab(); #endif } #endif #if MayFullScreen LOCALPROC UngrabMachine(void) { GrabMachine = false; AdjustMachineGrab(); } #endif /* --- basic dialogs --- */ LOCALPROC NativeStrFromCStr(ps3p r, char *s, bool AddEllipsis) { int i; int L; uint8_t 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 bool gBackgroundFlag = false; LOCALVAR bool gTrueBackgroundFlag = false; LOCALVAR bool CurSpeedStopped = true; LOCALVAR bool ADialogIsUp = false; LOCALPROC BeginDialog(void) { DisconnectKeyCodes3(); ADialogIsUp = true; #if MayFullScreen UngrabMachine(); #endif } LOCALPROC EndDialog(void) { #if HogCPU NoEventsCounter = 0; #endif ADialogIsUp = false; ReconnectKeyCodes3(); } #define kStandardAlert 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, false); NativeStrFromCStr(longMsgp, SavedLongMsg, false); #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, ¶m, &itemHit); } else #endif { ParamText(briefMsgp, longMsgp, "\p", "\p"); if (SavedFatalMsg) { while (StopAlert(kStandardAlert, NULL) != 1) { } } else { while (CautionAlert(kStandardAlert, NULL) != 1) { } } /* Alert (kStandardAlert, 0L); */ } SavedBriefMsg = nullpr; } } /* --- hide/show menubar --- */ #if MayFullScreen #if MightNotHaveWindows85Avail LOCALVAR RgnHandle GrayRgnSave = NULL; LOCALVAR short mBarHeightSave; #endif #endif #if MayFullScreen LOCALPROC _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(_GetGrayRgn(), GrayRgnSave); RectRgn(mBarRgn, &qd.screenBits.bounds); DiffRgn(mBarRgn, _GetGrayRgn(), mBarRgn); /* menu bar rgn, plus corner areas of main screen */ mBarHeightSave = _LMGetMBarHeight(); LMSetMBarHeight(0); UnionRgn(_GetGrayRgn(), mBarRgn, _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 _ShowMenuBar(void) { #if Windows85APIAvail if (HaveHideShowMenuAvail()) { if (! IsMenuBarVisible()) { ShowMenuBar(); } } else #endif { #if MightNotHaveWindows85Avail if (GrayRgnSave != NULL) { LMSetMBarHeight(mBarHeightSave); CopyRgn(GrayRgnSave, _GetGrayRgn()); /* PaintBehind(LMGetWindowList(), GrayRgnSave); CalcVisBehind(LMGetWindowList(), GrayRgnSave); */ DisposeRgn(GrayRgnSave); DrawMenuBar(); GrayRgnSave = NULL; #if 0 if (controlStripHidden) { controlStripHidden = false; if (noErr == Gestalt(gestaltControlStripVersion, &result)) { SBShowHideControlStrip(true); } } #endif } #endif } } #endif #if IncludePbufs LOCALVAR Handle PbufDat[NumPbufs]; #endif #if IncludePbufs LOCALFUNC tMacErr PbufNewFromHandle(Handle h, uint32_t 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(uint32_t 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 uint8_t * PbufLock(tPbuf i) { uint8_t * p; Handle h = PbufDat[i]; if (NULL == h) { p = nullpr; } else { HLock(h); p = (uint8_t *)*h; } return p; } #endif #if IncludePbufs LOCALPROC PbufUnlock(tPbuf i) { HUnlock(PbufDat[i]); } #endif #if IncludePbufs GLOBALOSGLUPROC PbufTransfer(uint8_t * Buffer, tPbuf i, uint32_t offset, uint32_t count, bool IsWrite) { Handle h = PbufDat[i]; HLock(h); { void *p = ((uint8_t *)*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) { uint32_t 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(bool IsWrite, uint8_t * Buffer, tDrive Drive_No, uint32_t Sony_Start, uint32_t Sony_Count, uint32_t *Sony_ActCount) { /* return 0 if it succeeds, nonzero (a Macintosh style error code, but -1 will do) on failure. */ tMacErr result; uint32_t 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, uint32_t *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; bool DidEject = false; short refnum = Drives[Drive_No]; result = GetVRefNum(refnum, &vRefNum); if (noErr == result) { DidEject = true; 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; bool DidEject = false; 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 = true; (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 = true; (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, bool 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, false); } else if (mnvm_opWrErr == err) { MacMsg(kStrImageInUseTitle, kStrImageInUseMessage, false); } else { MacMsg(kStrOpenFailTitle, kStrOpenFailMessage, false); } } } LOCALFUNC tMacErr InsertADiskFromFileRef(FSSpec *spec) { short refnum; tMacErr err; bool locked = false; err = To_tMacErr(FSpOpenDF(spec, fsRdWrPerm, &refnum)); switch (err) { case mnvm_permErr: case mnvm_wrPermErr: case mnvm_afpAccessDenied: locked = true; 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; bool locked = false; 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 = true; 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, bool MaybeROM, bool 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, true, false))) { } if (mnvm_noErr != err) { goto label_fail; } } } label_fail: return err; } LOCALFUNC tMacErr InsertADiskFromNameEtc(Dir_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, false, true); } } 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 == gMainWindow) { Update_Screen(); } EndUpdate(which); } break; } } } #endif #define PStrConstBlank ((ps3p)"\000") LOCALPROC InsertADisk0(void) { #if NavigationAvail #define DisposeNavEventUPP(userUPP) \ DisposeRoutineDescriptor(userUPP) #define DisposeNavObjectFilterUPP(userUPP) \ DisposeRoutineDescriptor(userUPP) #define NewNavObjectFilterUPP NewNavObjectFilterProc #define NewNavEventUPP NewNavEventProc if (HaveNavServicesAvail()) { NavReplyRecord theReply; NavDialogOptions dialogOptions; OSErr theErr = noErr; NavTypeListHandle openList = NULL; NavObjectFilterUPP filterUPP = NewNavObjectFilterUPP( /* (NavObjectFilterProcPtr) */ NavigationFilterProc); NavEventUPP eventUPP = NewNavEventUPP( /* (NavEventProcPtr) */ NavigationEventProc); theErr = NavGetDefaultDialogOptions(&dialogOptions); dialogOptions.dialogOptionFlags |= kNavDontAutoTranslate; /* dialogOptions.dialogOptionFlags &= ~ kNavAllowMultipleFiles; */ dialogOptions.dialogOptionFlags &= ~ kNavAllowPreviews; BeginDialog(); theErr = NavGetFile(NULL, &theReply, &dialogOptions, /* NULL */ eventUPP, NULL, filterUPP, (NavTypeListHandle)openList, NULL); EndDialog(); DisposeNavObjectFilterUPP(filterUPP); DisposeNavEventUPP(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; BeginDialog(); SFGetFile(*(Point *)&where, PStrConstBlank, NULL, -1 /* kNumFileTypes */, NULL /* fileTypes */, NULL, &reply); EndDialog(); if (reply.good) { ReportStandardOpenDiskError( InsertADiskFromNamevRef1(reply.fName, reply.vRefNum)); } } else #endif { StandardFileReply reply; BeginDialog(); StandardGetFile(0L, -1, 0L, &reply); EndDialog(); if (reply.sfGood) { ReportStandardOpenDiskError( InsertADiskOrAliasFromSpec(&reply.sfFile, true, false)); } } } #ifndef AppIsBundle #define AppIsBundle 0 #endif LOCALVAR Dir_R DatDir; #if AppIsBundle LOCALFUNC bool 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 true; } else { return false; } } #endif #if AppIsBundle LOCALFUNC bool 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 true; } return false; } #endif LOCALFUNC bool InitApplInfo(void) { #if HaveCPUfamM68K if (! HaveFSSpecCallsAvail()) { if (noErr == GetVol(NULL, &DatDir.VRefNum)) { DatDir.DirId = 0; return true; } } 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)) { DatDir.VRefNum = pb.ioFCBVRefNum; DatDir.DirId = pb.ioFCBParID; return true; } } return false; } LOCALFUNC tMacErr DirFromWD_v2(short VRefNum, Dir_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(Dir_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 = DirFromWD_v2(info.sysVRefNum, d); } } return err; } #define CatInfoIsFolder(cPB) \ (((cPB)->hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0) #define PStrLength(s) (*(s)) #define SizeOfListChar(n) (n) #define PStrToTotSize(s) (SizeOfListChar(PStrLength(s) + 1)) /* + 1 for length byte */ LOCALPROC PStrCopy(ps3p r, ps3p s) { MoveBytes((anyp)s, (anyp)r, PStrToTotSize(s)); } LOCALFUNC tMacErr FindNamedChildDir_v2(Dir_R *src_d, StringPtr s, Dir_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 ResolveAliasDir_v2(Dir_R *src_d, StringPtr s, Dir_R *dst_d) { tMacErr err; FSSpec spec; Boolean isFolder; Boolean isAlias; Dir_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 = FindNamedChildDir_v2(&src2_d, spec.name, dst_d); } } return err; } LOCALFUNC tMacErr ResolveNamedChildDir_v2(Dir_R *src_d, StringPtr s, Dir_R *dst_d) { tMacErr err; err = FindNamedChildDir_v2(src_d, s, dst_d); if (mnvm_dirNFErr == err) { if (HaveAliasMgrAvail()) { err = ResolveAliasDir_v2(src_d, s, dst_d); } } return err; } LOCALFUNC tMacErr OpenNamedFileInFolderCStr(Dir_R *d, char *s, short *refnum) { Str255 fileName; PStrFromCStr(fileName, s); return OpenNamedFileInFolder(d, fileName, refnum); } LOCALFUNC tMacErr ResolveNamedChildDirCStr(Dir_R *src_d, char *s, Dir_R *dst_d) { Str255 fileName; PStrFromCStr(fileName, s); return ResolveNamedChildDir_v2(src_d, fileName, dst_d); } LOCALFUNC tMacErr LoadMacRomFromNameFolder(Dir_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; Dir_R PrefRef; Dir_R GryphelRef; Dir_R ROMsRef; if (mnvm_noErr == (err = FindPrefFolder(&PrefRef))) if (mnvm_noErr == (err = ResolveNamedChildDirCStr(&PrefRef, "Gryphel", &GryphelRef))) if (mnvm_noErr == (err = ResolveNamedChildDirCStr(&GryphelRef, "mnvm_rom", &ROMsRef))) if (mnvm_noErr == (err = LoadMacRomFromNameFolder(&ROMsRef, RomFileName))) { /* ok */ } return err; } LOCALFUNC bool LoadMacRom(void) { tMacErr err; if (mnvm_fnfErr == (err = LoadMacRomFromNameFolder(&DatDir, RomFileName))) if (mnvm_fnfErr == (err = LoadMacRomFromPrefDir())) { } return true; /* keep launching Mini vMac, regardless */ } LOCALFUNC bool Sony_InsertIth(int i) { if ((i > 9) || ! FirstFreeDisk(nullpr)) { return false; } else { Str255 s; tMacErr err = mnvm_noErr; PStrFromCStr(s, "disk?.dsk"); s[5] = '0' + i; if (! CheckSavetMacErr(InsertADiskFromNameEtc(&DatDir, s))) { if (mnvm_fnfErr != err) { ReportStandardOpenDiskError(err); } return false; } return true; } } LOCALFUNC bool LoadInitialImages(void) { int i; for (i = 1; Sony_InsertIth(i); ++i) { /* stop on first error (including file not found) */ } return true; } #if IncludeSonyNew LOCALFUNC tMacErr WriteZero(SInt16 refnum, uint32_t L) { #define ZeroBufferSize 2048 tMacErr err; uint32_t i; uint8_t 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, uint32_t 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, false, 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, uint32_t 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, false, 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 MakeNamedDir_v2(Dir_R *d, StringPtr s, Dir_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(Dir_R *new_d, Dir_R *d, StringPtr s) { tMacErr err; err = ResolveNamedChildDir_v2(d, s, new_d); if (mnvm_fnfErr == err) { err = MakeNamedDir_v2(d, s, new_d); } return err; } #endif #if UseActvFile || (IncludeSonyNew && ! SaveDialogEnable) LOCALFUNC tMacErr FindOrMakeChildDirCStr(Dir_R *new_d, Dir_R *d, char *name) { Str255 s; PStrFromCStr(s, name); return FindOrMakeMakeNamedDir_v2(new_d, d, s); } #endif #if IncludeSonyNew LOCALPROC MakeNewDisk(uint32_t L, Handle NewDiskName) { #if SaveDialogEnable OSErr theErr; #if NavigationAvail if (HaveNavServicesAvail()) { NavReplyRecord theReply; NavDialogOptions dialogOptions; NavEventUPP eventUPP = NewNavEventUPP( /* (NavEventProcPtr) */ NavigationEventProc); theErr = NavGetDefaultDialogOptions(&dialogOptions); dialogOptions.dialogOptionFlags |= kNavNoTypePopup; #if IncludeSonyNameNew if (NewDiskName != NULL) { PStrFromHandle(dialogOptions.savedFileName, NewDiskName, 255); } #endif BeginDialog(); theErr = NavPutFile(NULL, &theReply, &dialogOptions, /* NULL */ eventUPP, '????', '????', NULL); EndDialog(); DisposeNavEventUPP(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", false); } NativeStrFromCStr(prompt, "Please select a file", false); #if HaveCPUfamM68K if (! HaveFSSpecCallsAvail()) { Point where; SFReply reply; where.h = 50; where.v = 50; BeginDialog(); SFPutFile(*(Point *)&where, prompt, Title, NULL, &reply); EndDialog(); if (reply.good) { MakeNewDiskFromNamevRef(reply.fName, reply.vRefNum, L); } } else #endif { StandardFileReply reply; BeginDialog(); StandardPutFile(prompt, Title, &reply); EndDialog(); if (reply.sfGood) { MakeNewDiskFromSpec(&reply.sfFile, L); } } } #else /* SaveDialogEnable */ tMacErr err; Str255 Title; Dir_R OutDir; FSSpec spec; #if IncludeSonyNameNew if (NewDiskName != NULL) { PStrFromHandle(Title, NewDiskName, 255); } else #endif { NativeStrFromCStr(Title, "untitled", false); } if (mnvm_noErr == (err = FindOrMakeChildDirCStr(&OutDir, &DatDir, "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 CreateFile_v2(Dir_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 DeleteFile_v2(Dir_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 CreateFileOverWrite_v2(Dir_R *d, StringPtr s) { tMacErr err; err = CreateFile_v2(d, s); if (mnvm_dupFNErr == err) { if (mnvm_noErr == (err = DeleteFile_v2(d, s))) { err = CreateFile_v2(d, s); } } return err; } LOCALFUNC tMacErr FileOpen_v2(Dir_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 FileOpenWrite_v2(Dir_R *d, StringPtr s, short *refnum) { return FileOpen_v2(d, s, (char)fsWrPerm, refnum); } LOCALFUNC tMacErr OpenOverWriteFile_v2(Dir_R *d, StringPtr s, short *refnum) { tMacErr err; err = CreateFileOverWrite_v2(d, s); if (mnvm_noErr == err) { err = FileOpenWrite_v2(d, s, refnum); if (mnvm_noErr != err) { (void) DeleteFile_v2(d, s); /* ignore any error, since already got one */ } } return err; } LOCALFUNC tMacErr OpenOverWriteFileCStr(Dir_R *d, char *name, short *refnum) { Str255 s; PStrFromCStr(s, name); return OpenOverWriteFile_v2(d, s, refnum); } #define ActvCodeFileName "act_1" LOCALFUNC tMacErr OpenActvCodeFile(short *refnum) { tMacErr err; Dir_R PrefRef; Dir_R GryphelRef; Dir_R ActRef; if (mnvm_noErr == (err = FindPrefFolder(&PrefRef))) if (mnvm_noErr == (err = ResolveNamedChildDirCStr(&PrefRef, "Gryphel", &GryphelRef))) if (mnvm_noErr == (err = ResolveNamedChildDirCStr(&GryphelRef, "mnvm_act", &ActRef))) if (mnvm_noErr == (err = OpenNamedFileInFolderCStr(&ActRef, ActvCodeFileName, refnum))) { /* ok */ } return err; } LOCALFUNC tMacErr ActvCodeFileLoad(uint8_t * 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(uint8_t * p) { tMacErr err; short refnum; Dir_R PrefRef; Dir_R GryphelRef; Dir_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 = OpenOverWriteFileCStr(&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 bool 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 true; } else if (noErr == theErr) { /* More required params! */ return /* CheckSysCode(errAEEventNotHandled) */ false; } else { /* Unexpected Error! */ return /* CheckSysCode(theErr) */ false; } } LOCALFUNC bool 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 true; } else if (noErr == theErr) { /* More required params! */ return true; /* errAEEventNotHandled; */ /*^*/ } else { /* Unexpected Error! */ return /* CheckSysCode(theErr) */ false; } } /* 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 = true; } return /* GetASysResultCode() */ 0; } #define NewAEEventHandlerUPP NewAEEventHandlerProc LOCALFUNC bool InstallEventHandler(AEEventClass theAEEventClass, AEEventID theAEEventID, ProcPtr p, long handlerRefcon, bool isSysHandler) { return noErr == (AEInstallEventHandler(theAEEventClass, theAEEventID, #if /* useUPP */ 1 NewAEEventHandlerUPP((AEEventHandlerProcPtr)p), #else (AEEventHandlerUPP)p, #endif handlerRefcon, isSysHandler)); } LOCALPROC InstallAppleEventHandlers(void) { if (noErr == AESetInteractionAllowed(kAEInteractWithLocal)) if (InstallEventHandler(kCoreEventClass, kAEOpenApplication, (ProcPtr)DoOpenEvent, 0, false)) if (InstallEventHandler(kCoreEventClass, kAEOpenDocuments, (ProcPtr)OpenOrPrintFiles, openOnly, false)) if (InstallEventHandler(kCoreEventClass, kAEPrintDocuments, (ProcPtr)OpenOrPrintFiles, openPrint, false)) if (InstallEventHandler(kCoreEventClass, kAEQuitApplication, (ProcPtr)DoQuitEvent, 0, false)) { } } #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, true, true)); } } if (gTrueBackgroundFlag) { ProcessSerialNumber currentProcess = {0, kCurrentProcess}; (void) SetFrontProcess(¤tProcess); WantCmdOptOnReconnect = true; } } return noErr; } #endif #if EnableDragDrop static DragReceiveHandlerUPP gGlobalReceiveHandler = NULL; #endif #if EnableDragDrop #define NewDragTrackingHandlerUPP NewDragTrackingHandlerProc #define NewDragReceiveHandlerUPP NewDragReceiveHandlerProc #if ! OPAQUE_UPP_TYPES #define DisposeDragReceiveHandlerUPP(userUPP) \ DisposeRoutineDescriptor(userUPP) #define DisposeDragTrackingHandlerUPP(userUPP) \ DisposeRoutineDescriptor(userUPP) #else #define DisposeDragReceiveHandlerUPP DisposeDragReceiveHandlerUPP #define DisposeDragTrackingHandlerUPP DisposeDragTrackingHandlerUPP #endif #endif #if EnableDragDrop LOCALPROC UnPrepareForDragging(void) { if (NULL != gGlobalReceiveHandler) { RemoveReceiveHandler(gGlobalReceiveHandler, gMainWindow); DisposeDragReceiveHandlerUPP(gGlobalReceiveHandler); gGlobalReceiveHandler = NULL; } if (NULL != gGlobalTrackingHandler) { RemoveTrackingHandler(gGlobalTrackingHandler, gMainWindow); DisposeDragTrackingHandlerUPP(gGlobalTrackingHandler); gGlobalTrackingHandler = NULL; } } #endif #if EnableDragDrop LOCALFUNC bool PrepareForDragging(void) { bool IsOk = false; gGlobalTrackingHandler = NewDragTrackingHandlerUPP( GlobalTrackingHandler); if (gGlobalTrackingHandler != NULL) { gGlobalReceiveHandler = NewDragReceiveHandlerUPP( GlobalReceiveHandler); if (gGlobalReceiveHandler != NULL) { if (noErr == InstallTrackingHandler(gGlobalTrackingHandler, gMainWindow, nil)) { if (noErr == InstallReceiveHandler( gGlobalReceiveHandler, gMainWindow, nil)) { IsOk = true; } } } } return IsOk; } #endif #if EnableMagnify #define ScaleBuffSzMult (WindowScale * WindowScale) #endif LOCALFUNC bool CreateNewWindow(Rect *Bounds, WindowPtr *theWindow) { WindowPtr ResultWin; bool IsOk = false; 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 = true; } return IsOk; } LOCALPROC ZapWState(void) { gMainWindow = NULL; gGlobalReceiveHandler = NULL; gGlobalTrackingHandler = NULL; } LOCALPROC CloseMainWindow(void) { /* Dispose of anything set up by CreateMainWindow. */ #if EnableDragDrop UnPrepareForDragging(); #endif if (gMainWindow != NULL) { DisposeWindow(gMainWindow); gMainWindow = NULL; } } enum { kMagStateNormal, #if EnableMagnify kMagStateMagnifgy, #endif kNumMagStates }; #define kMagStateAuto kNumMagStates #if MayNotFullScreen LOCALVAR int CurWinIndx; LOCALVAR bool HavePositionWins[kNumMagStates]; LOCALVAR Point WinPositionWins[kNumMagStates]; #endif LOCALFUNC bool 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; bool IsOk = false; #if VarFullScreen if (UseFullScreen) { _HideMenuBar(); } else { _ShowMenuBar(); } #else #if MayFullScreen _HideMenuBar(); #endif #endif GetGrayRgnBounds(&AllScrnBounds); GetScreenBitsBounds(&MainScrnBounds); #if EnableMagnify if (UseMagnify) { NewWindowHeight *= WindowScale; NewWindowWidth *= WindowScale; } #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 /= WindowScale; ViewVSize /= WindowScale; } #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] = true; 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 (CreateNewWindow(&NewWinRect, &gMainWindow)) { ShowWindow(gMainWindow); /* check if window rect valid */ #if VarFullScreen if (! UseFullScreen) #endif #if MayNotFullScreen { Rect tr; if (GetWindowTitleBounds(gMainWindow, &tr)) { if (! RectInRgn(&tr, _GetGrayRgn())) { SetMacWindContRect(gMainWindow, &MainScrnBounds); if (GetWindowTitleBounds(gMainWindow, &tr)) { if (! RectInRgn(&tr, _GetGrayRgn())) { OffsetRect(&MainScrnBounds, 0, AllScrnBounds.top - tr.top); SetMacWindContRect(gMainWindow, &MainScrnBounds); } } } } } #endif #if EnableDragDrop if (HaveDragMgrAvail()) { (void) PrepareForDragging(); } #endif IsOk = true; } return IsOk; } struct WState { WindowPtr f_MainWindow; #if MayFullScreen short f_hOffset; short f_vOffset; uint16_t f_ViewHSize; uint16_t f_ViewVSize; uint16_t f_ViewHStart; uint16_t f_ViewVStart; #endif #if VarFullScreen bool f_UseFullScreen; #endif #if EnableMagnify bool f_UseMagnify; #endif #if MayNotFullScreen int f_CurWinIndx; #endif DragTrackingHandlerUPP f_gGlobalTrackingHandler; DragReceiveHandlerUPP f_gGlobalReceiveHandler; }; typedef struct WState WState; LOCALPROC GetWState(WState *r) { r->f_MainWindow = gMainWindow; #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 SetWState(WState *r) { gMainWindow = 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 bool 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 false. otherwise, if succeed, return true) i.e. can allocate the new one before disposing of the old one. */ WState old_state; WState new_state; #if VarFullScreen if (! UseFullScreen) #endif #if MayNotFullScreen { /* save old position */ if (gMainWindow != NULL) { Rect r; if (GetWindowContBounds(gMainWindow, &r)) { WinPositionWins[CurWinIndx].h = r.left; WinPositionWins[CurWinIndx].v = r.top; } } } #endif #if MayFullScreen UngrabMachine(); #endif GetWState(&old_state); ZapWState(); #if VarFullScreen UseFullScreen = WantFullScreen; #endif #if EnableMagnify UseMagnify = WantMagnify; #endif ColorTransValid = false; if (! CreateMainWindow()) { CloseMainWindow(); SetWState(&old_state); #if VarFullScreen if (UseFullScreen) { _HideMenuBar(); } else { _ShowMenuBar(); } #endif /* avoid retry */ #if VarFullScreen WantFullScreen = UseFullScreen; #endif #if EnableMagnify WantMagnify = UseMagnify; #endif return false; } else { GetWState(&new_state); SetWState(&old_state); CloseMainWindow(); SetWState(&new_state); if (HaveCursorHidden) { (void) MoveMouse(CurMouseH, CurMouseV); WantCursorHidden = true; } return true; } } #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] = false; } } #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 = false; if (WantFullScreen) { Rect r; GetScreenBitsBounds(&r); if (((r.right - r.left) >= vMacScreenWidth * WindowScale) && ((r.bottom - r.top) >= vMacScreenHeight * WindowScale) ) { WantMagnify = true; } } } } #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 SoundEnabled Sound_Start(); #endif StartUpTimeAdjust(); } LOCALPROC EnterSpeedStopped(void) { #if SoundEnabled Sound_Stop(); #endif } LOCALPROC CheckForSavedTasks(void) { if (EvtQNeedRecover) { EvtQNeedRecover = false; /* attempt cleanup, EvtQNeedRecover may get set again */ EvtQTryRecoverFromFull(); } #if EnableFSMouseMotion if (HaveMouseMotion) { MouseConstrain(); } #endif if (RequestMacOff) { RequestMacOff = false; if (AnyDiskInserted()) { MacMsgOverride(kStrQuitWarningTitle, kStrQuitWarningMessage); } else { ForceMacOff = true; } } 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 = false; 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 = false; /* must be done after may have gotten disk */ } #endif if (RequestInsertDisk) { RequestInsertDisk = false; 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 bool 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 = true; break; case kFileQuitItem: RequestMacOff = true; 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; GetScreenBitsBounds(&r); DragWindow(whichWindow, theEvent->where, &r); } break; case inContent: if (FrontWindow() != whichWindow) { SelectWindow(whichWindow); } if (whichWindow == gMainWindow) { MousePositionNotifyFromGlobal(theEvent->where); MouseButtonSet(true); } break; case inGoAway: if (TrackGoAway(whichWindow, theEvent->where)) { RequestMacOff = true; } break; case inZoomIn: case inZoomOut: /* Zoom Boxes */ break; } break; case mouseUp: MousePositionNotifyFromGlobal(theEvent->where); MouseButtonSet(false); break; case updateEvt: GetPort(&savePort); BeginUpdate((WindowPtr) theEvent->message); if ((WindowPtr)theEvent->message == gMainWindow) { 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 = false; } else { gTrueBackgroundFlag = true; } } 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 ((uint8_t) -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; bool PrivateEvent = false; switch (theEvent.what) { case keyDown: case autoKey: case keyUp: case mouseUp: PrivateEvent = true; break; case mouseDown: if ((inContent == FindWindow(theEvent.where, &whichWindow)) && (whichWindow == gMainWindow) && (FrontWindow() == whichWindow)) { PrivateEvent = true; } 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 SoundEnabled Sound_SecondNotify(); #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, bool 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, false); return NewMenu(menuID, r); } LOCALFUNC bool InstallOurMenus(void) { MenuHandle menu; Str255 s; PStrFromChar(s, (char)20); menu = NewMenu(kAppleMenu, s); if (menu != NULL) { AppendMenuConvertCStr(menu, kStrMenuItemAbout, true); AppendMenuSep(menu); AppendResMenu(menu, 'DRVR'); InsertMenu(menu, 0); } menu = NewMenuFromConvertCStr(kFileMenu, kStrMenuFile); if (menu != NULL) { AppendMenuConvertCStr(menu, kStrMenuItemOpen, true); { AppendMenuSep(menu); AppendMenuConvertCStr(menu, kStrMenuItemQuit, false); } InsertMenu(menu, 0); } menu = NewMenuFromConvertCStr(kSpecialMenu, kStrMenuSpecial); if (menu != NULL) { AppendMenuConvertCStr(menu, kStrMenuItemMore, true); InsertMenu(menu, 0); } DrawMenuBar(); return true; } #if AppearanceAvail LOCALFUNC bool InstallOurAppearanceClient(void) { if (HaveAppearanceAvail()) { RegisterAppearanceClient(); } return true; } #endif LOCALFUNC bool InstallOurEventHandlers(void) { InitKeyCodes(); if (HaveAppleEvtMgrAvail()) { InstallAppleEventHandlers(); } return true; } 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, false); ReserveAllocOneBlock(&screencomparebuff, vMacScreenNumBytes, 5, true); #if UseControlKeys ReserveAllocOneBlock(&CntrlDisplayBuff, vMacScreenNumBytes, 5, false); #endif #if EnableMagnify ReserveAllocOneBlock(&ScalingBuff, vMacScreenNumBytes * (ScaleBuffSzMult), 5, false); ReserveAllocOneBlock(&ScalingTabl, ScalingTablsz, 5, false); #endif #if SoundEnabled ReserveAllocOneBlock((uint8_t * *)&TheSoundBuffer, dbhBufferSize, 5, false); #endif EmulationReserveAlloc(); } LOCALFUNC bool AllocMemory(void) { uimr n; bool IsOk = false; ReserveAllocOffset = 0; ReserveAllocBigBlock = nullpr; ReserveAllocAll(); n = ReserveAllocOffset; ReserveAllocBigBlock = (uint8_t *)NewPtr(n); if (NULL == ReserveAllocBigBlock) { MacMsg(kStrOutOfMemTitle, kStrOutOfMemMessage, true); } else { ReserveAllocOffset = 0; ReserveAllocAll(); if (n != ReserveAllocOffset) { /* oops, program error */ } else { IsOk = true; } } return IsOk; } LOCALFUNC bool InitOSGLU(void) { /* run all the initializations needed for the program. */ if (InitMacManagers()) if (AllocMemory()) if (InitApplInfo()) #if dbglog_HAVE if (dbglog_open()) #endif #if AppearanceAvail if (InstallOurAppearanceClient()) #endif if (InstallOurEventHandlers()) if (InstallOurMenus()) #if SoundEnabled if (Sound_Init()) #endif if (ReCreateMainWindow()) if (LoadMacRom()) if (LoadInitialImages()) if (InitLocationDat()) if (WaitForRom()) { return true; } return false; } LOCALPROC UnInitOSGLU(void) { /* Do all clean ups needed before the program quits. */ if (MacMsgDisplayed) { MacMsgDisplayOff(); } #if MayFullScreen UngrabMachine(); #endif #if SoundEnabled Sound_Stop(); #endif CloseMainWindow(); #if MayFullScreen _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 }