home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacFormat 1995 March
/
macformat-022.iso
/
Shareware City
/
Developers
/
MA3.1.1 & CW4.5
/
Modifications
/
*OR* replace these files
/
UMacAppGlobals.cp
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS
UTF-8
Wrap
Text File
|
1994-09-17
|
54.1 KB
|
1,910 lines
|
[
TEXT/MPS
]
/*
* This file has been changed from the original MacApp 3.1.1
* to support the metrowerks CodeWarrior compilers C/C++ 1.1.1.
* These changes are known *not* to work with earlier versions
* of CodeWarrior. Every attempt though has been made to to keep
* this file compatible with other development environments.
*
* Mark Anderson
* metrowerks
* 9/16/94
*
*/
//----------------------------------------------------------------------------------------
// UMacAppGlobals.cp
// Copyright © 1984-1994 by Apple Computer Inc. All rights reserved.
//----------------------------------------------------------------------------------------
#ifndef __UMACAPPGLOBALS__
#include "UMacAppGlobals.h"
#endif
#ifndef __ULIST__
#include <UList.h>
#endif
#ifndef __APPLEEVENTS__
#include <AppleEvents.h>
#endif
#ifndef __EDITIONS__
#include <Editions.h>
#endif
#ifndef __UAPPLEEVENTS__
#include <UAppleEvents.h>
#endif
#ifndef __UEVENT__
#include <UEvent.h>
#endif
#ifndef __UCOMMAND__
#include <UCommand.h>
#endif
#ifndef __UDESIGNATOR__
#include <UDesignator.h>
#endif
#ifndef __UEVENTHANDLER__
#include <UEventHandler.h>
#endif
#ifndef __UAPPLICATION__
#include <UApplication.h>
#endif
#ifndef __UDOCUMENT__
#include <UDocument.h>
#endif
#ifndef __UFILEBASEDDOCUMENT__
#include <UFileBasedDocument.h>
#endif
#ifndef __UPRINTHANDLER__
#include <UPrintHandler.h>
#endif
#ifndef __BALLOONS__
#include <Balloons.h>
#endif
#ifndef __UVIEW__
#include <UView.h>
#endif
#ifndef __USTREAM__
#include <UStream.h>
#endif
#ifndef __UADORNERS__
#include <UAdorners.h>
#endif
#ifndef __UWINDOW__
#include <UWindow.h>
#endif
#ifndef __CONTROLS__
#include <Controls.h>
#endif
#ifndef __UCONTROL__
#include <UControl.h>
#endif
#ifndef __USCROLLER__
#include <UScroller.h>
#endif
#ifndef __UMACAPPUTILITIES__
#include <UMacAppUtilities.h>
#endif
#ifndef __UERRORMGR__
#include <UErrorMgr.h>
#endif
#ifndef __UMEMORY__
#include <UMemory.h>
#endif
#ifndef __ERRORS__
#include <Errors.h>
#endif
#ifndef __TOOLUTILS__
#include <ToolUtils.h>
#endif
#ifndef __UBUSYCURSOR__
#include <UBusyCursor.h>
#endif
#ifndef __UDEBUG__
#include <UDebug.h>
#endif
#ifndef __UDEPENDENCIES__
#include <UDependencies.h>
#endif
#ifndef __MENUS__
#include <Menus.h>
#endif
#ifndef __UMENUMGR__
#include <UMenuMgr.h>
#endif
#ifndef __SCRAP__
#include <Scrap.h>
#endif
#ifndef __UCLIPBOARDMGR__
#include <UClipboardMgr.h>
#endif
#ifndef __UDESKSCRAPVIEW__
#include <UDeskScrapView.h>
#endif
#ifndef __USYNCHSCROLLER__
#include <USynchScroller.h>
#endif
#ifndef __RESOURCES__
#include <Resources.h>
#endif
#ifndef __FONTS__
#include <Fonts.h>
#endif
#ifndef __PACKAGES__
#include <Packages.h>
#endif
#ifndef __SCRIPT__
#include <Script.h>
#endif
#ifndef __DEVICES__
#include <Devices.h>
#endif
#ifndef __STDIO__
#include <stdio.h>
#endif
#ifndef __FOLDERS__
#include <Folders.h>
#endif
#ifndef __OSEVENTS__
#include <OSEvents.h>
#endif
#ifndef __GESTALTEQU__
#include <GestaltEqu.h>
#endif
#ifndef __PROCESSES__
#include <Processes.h>
#endif
#ifndef __STDLIB__
#include <stdlib.h>
#endif
#ifndef __LOWMEM__
#include <LowMem.h>
#endif
//----------------------------------------------------------------------------------------
#if qPowerPC && !defined(__MWERKS__)
QDGlobals qd;
#endif
Boolean gCouldPrint;
TDynamicArray* gSignatures;
TextStyle gSystemStyle;
TextStyle gApplicationStyle;
TextStyle gApplicationStyle9;
WindowPtr gWorkPort;
RgnHandle gTemporaryRegion = NULL;
RgnHandle CTemporaryRegion::fCachedRgn = NULL;
NMRecPtr gNotificationPtr = NULL;
ModalFilterYDProcPtr gModalFilterYDProcPtr = MacAppStandardFileFilter;
#if qDebug
Boolean gBusyTemporaryRegion = false;
CStr255 gUsedBy = "";
#endif
FailInfo pFi;
//========================================================================================
// CLASS PatchExitToShell
//========================================================================================
#pragma segment MAGlobalsRes
typedef pascal void (*ExitToShellType)(void);
enum
{
uppExitToShellProcInfo = kPascalStackBased
};
#if USESROUTINEDESCRIPTORS
typedef UniversalProcPtr ExitToShellUPP;
#define CallExitToShellProc(userRoutine) \
CallUniversalProc((UniversalProcPtr)(userRoutine), uppExitToShellProcInfo)
#define NewExitToShellProc(userRoutine) \
(ExitToShellUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppExitToShellProcInfo, GetCurrentISA())
#else
typedef ProcPtr ExitToShellUPP;
#define CallExitToShellProc(userRoutine) \
(*(userRoutine))()
#define NewExitToShellProc(userRoutine) \
(ExitToShellUPP)(userRoutine)
#endif
class PatchExitToShell : public TrapPatch
{
public:
void Install(ExitToShellType routine);
void CallInherited(void);
};
//--------------------------------------------------------------------------------------------------
#pragma segment MAInit
void PatchExitToShell::Install(ExitToShellType routine)
{
patchRoutine = NewExitToShellProc(StripLong(routine));
FailNIL(patchRoutine);
PatchTrap(_ExitToShell, patchRoutine);
}
//--------------------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
void PatchExitToShell::CallInherited(void)
{
CallExitToShellProc((ExitToShellType) oldTrapAddr);
}
//--------------------------------------------------------------------------------------------------
PatchExitToShell pETSPatch;
//========================================================================================
// GLOBAL Functions
//========================================================================================
//----------------------------------------------------------------------------------------
// GetAlertButtonTitle: Retrieve the title of the button control. If itemNo isn't a
// button, then return ''.
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
void GetAlertButtonTitle(DialogPtr theDialog,
short itemNo,
CStr255& theTitle)
{
short itemType;
Handle item;
Rect box;
theTitle = "";
GetDialogItem(theDialog, itemNo, &itemType, &item, &box);
if (itemType == (ctrlItem + btnCtrl))
GetControlTitle((ControlHandle)item, theTitle);
} // GetAlertButtonTitle
//----------------------------------------------------------------------------------------
// DoAlertKeyDown: Handle a keypress that has been mapped to one of the button controls.
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
void DoAlertKeyDown(DialogPtr theDialog, short itemNo)
{
short itemType;
Handle item;
Rect box;
long finalTicks;
GetDialogItem(theDialog, itemNo, &itemType, &item, &box);
if (itemType == (ctrlItem + btnCtrl))
{
// this code gives visual feedback
HiliteControl((ControlHandle)item, inButton); // hilite the button
Delay(8, &finalTicks); // delay for 8 ticks
HiliteControl((ControlHandle)item, 0); // stop hiliting the button
}
} // DoAlertKeyDown
//----------------------------------------------------------------------------------------
// CompareAlertKeysToItem: Compares the buffered multi-byte chars to the first character
// of each button title 1st button in alert (by convention == "OK"). 2nd button in alert
// (by convention == "Cancel"). 3rd button in alert (by convention == "No")
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
Boolean CompareAlertKeysToItem(DialogPtr theDialog,
CStr31& theChars,
short& itemHit)
{
CStr255 title;
GetAlertButtonTitle(theDialog, ok, title);
if (CompareMultiByteChars(theChars, title, false))
{
itemHit = ok;
return true;
}
GetAlertButtonTitle(theDialog, cancel, title);
if (CompareMultiByteChars(theChars, title, false))
{
itemHit = cancel;
return true;
}
GetAlertButtonTitle(theDialog, kNoButton, title);
if (CompareMultiByteChars(theChars, title, false))
{
itemHit = kNoButton;
return true;
}
return false;
} // CompareAlertKeysToItem
//----------------------------------------------------------------------------------------
// DrawDefaultProc: Draw the thick rounded rectangle around the default button
// (Imported to MacApp from Ponnuki by GA)
//
// This routine uses Keith Rollin's algorithm, as presented in the USENET Guide to
// Programming the Macintosh. I have modified the basic algorithm only slightly--I add
// two to the calculated 'buttonOval' value. This gets better results, particularly for
// buttons of the default size (18 points).
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
void DrawDefaultProc(DialogPtr dlog)
{
short defaultButton;
// Don't call GetDialogItem if the default button # has a strange value
defaultButton = ((DialogPeek)dlog)->aDefItem;
if( defaultButton > 0 )
{
GrafPtr savePort;
short type = 0;
ControlHandle buttonHandle = NULL;
CRect outlineBox;
GetPort(&savePort);
SetPort( dlog );
GetDialogItem(dlog, defaultButton, &type, (Handle *) &buttonHandle, outlineBox);
InsetRect(outlineBox,-4,-4);
// Don't draw the bold outline around the default button
// unless it really is a button
if( type == ctrlItem + btnCtrl )
{
PenState saveState;
short buttonOval;
GetPenState( &saveState );
// We want to draw the thick line with a normal
// pen pattern that is 3 pixels wide
PenNormal();
PenSize(3,3);
// If the button we are outlining is disabled,
// draw the outline with a gray pattern.
if( (*buttonHandle)->contrlHilite == 255 )
{
PenPat(&qd.gray);
}
// Calculate the curvature to use and draw the thick line
buttonOval = 2 + (outlineBox.bottom - outlineBox.top) / 2;
FrameRoundRect(outlineBox,buttonOval,buttonOval);
SetPenState( &saveState );
}
SetPort(savePort);
}
} // DrawDefaultProc
//----------------------------------------------------------------------------------------
// MinimalAlertFilter: This is the minimally-functional alert filter that MacApp uses
// in cases where gApplication has not yet been initialized. TApplication.AlertFilter
// calls this filter as well.
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
pascal Boolean MinimalAlertFilter(DialogPtr theDialog,
EventRecord& theEvent,
short& itemHit)
{
Boolean returnValue = false;
switch( theEvent.what )
{
case updateEvt:
{
if (((DialogPtr)theEvent.message) == theDialog)
{
DrawDefaultProc(theDialog);
}
break;
}
case keyDown:
{
unsigned char theChar = (unsigned char)(((theEvent.message) & charCodeMask));
if ((theChar == chEnter) || (theChar == chReturn))
{
itemHit = ((DialogPeek)theDialog)->aDefItem;
DoAlertKeyDown(theDialog, itemHit);
returnValue = true;
}
else if ( (theChar == '`') || (theChar == chEscape) || ((theChar == '.') && (theEvent.modifiers & cmdKey)))
{
DoAlertKeyDown(theDialog, cancel);
itemHit = cancel;
returnValue = true;
}
break;
}
}
return returnValue;
} // MinimalAlertFilter
//----------------------------------------------------------------------------------------
// MacAppAlertFilter:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
pascal Boolean MacAppAlertFilter(DialogPtr theDialog,
EventRecord& theEvent,
short& itemHit)
{
if (gApplication)
return gApplication->AlertFilter(theDialog, theEvent, itemHit);
else
return MinimalAlertFilter(theDialog, theEvent, itemHit);
} // MacAppAlertFilter
//----------------------------------------------------------------------------------------
// MacAppAppleEventIdleProc:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
pascal Boolean MacAppAppleEventIdleProc(EventRecord& theEventRecord,
long& sleepTime,
RgnHandle& mouseRgn)
{
if (gApplication)
return gApplication->AppleEventIdleProc(theEventRecord, sleepTime, mouseRgn);
else
return false;
} // MacAppAppleEventIdleProc
//----------------------------------------------------------------------------------------
// MacAppStandardFileFilter:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
pascal Boolean MacAppStandardFileFilter(DialogPtr theDialog,
EventRecord* theEvent,
short* itemHit,
void *yourDataPtr)
{
if (gApplication)
return gApplication->StandardFileFilter(theDialog, *theEvent, *itemHit, yourDataPtr);
else
return false;
} // MacAppStandardFileFilter
//----------------------------------------------------------------------------------------
// ApplicationBeep:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
void ApplicationBeep()
{
if (gApplication)
gApplication->Beep(2);
else
SysBeep(2);
} // ApplicationBeep
//----------------------------------------------------------------------------------------
// CleanupMacApp:
//----------------------------------------------------------------------------------------
#pragma push
#pragma trace off
#pragma segment MAGlobalsRes
void CleanupMacApp(void)
{
SetResLoad(true); // Make sure segments can load
pETSPatch.UnpatchTrap(); // Guaranteed not to fail
if (gApplication)
gApplication->Terminate();
gBusyCursor = (TBusyCursor *)FreeIfObject(gBusyCursor);
if (qNeedsAppleEventMgr || gConfiguration.hasAppleEventMgr)
AEDisposeDesc(&gServerAddress);
if (gTopHandler)
gTopHandler->Success(); // Remove the outermost failure handler
#if qDebug
DebugTerminate();
#endif
UnpatchAll();
gApplication = (TApplication*) FreeIfObject(gApplication);
} // CleanupMacApp
#pragma pop
//----------------------------------------------------------------------------------------
// ExitToShellCleanupMacApp:
//----------------------------------------------------------------------------------------
#pragma push
#pragma trace off
#pragma segment MAGlobalsRes
pascal void ExitToShellCleanupMacApp(void)
{
long OldA5 = SetCurrentA5(); // ***** Called from trap patches *****
ExitToShellType oldTrapAddr = (ExitToShellType) pETSPatch.GetOldTrapAddr();
CleanupMacApp();
CallExitToShellProc(oldTrapAddr);
SetA5(OldA5);
} // ExitToShellCleanupMacApp
#pragma pop
//----------------------------------------------------------------------------------------
// DoneWithTemporaryRegion: Indicates that gTemporaryRegion is no longer in use. Call this
// only if qDebug is true.
//----------------------------------------------------------------------------------------
#if qDebug
#pragma segment MADebug
void DoneWithTemporaryRegion()
{
if (!gBusyTemporaryRegion)
ProgramBreak("DoneWithTemporaryRegion called, but gTemporaryRegion is not locked");
gBusyTemporaryRegion = false;
gUsedBy = "";
SetEmptyRgn(gTemporaryRegion);
} // DoneWithTemporaryRegion
#endif
//----------------------------------------------------------------------------------------
// EnterDebugger:
//----------------------------------------------------------------------------------------
#if qDebug
#pragma segment MADebug
void EnterDebugger(Boolean entering)
{
if (gBusyCursor)
gBusyCursor->Activate(!entering);
} // EnterDebugger
#endif
//----------------------------------------------------------------------------------------
// ExitMacApp:
//----------------------------------------------------------------------------------------
#pragma segment MATerminate
void ExitMacApp()
{
ExitToShell();
// patch will call CleanupMacApp
} // ExitMacApp
//----------------------------------------------------------------------------------------
// FreeIfWMgrWindow:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
WindowPtr FreeIfWMgrWindow(WindowPtr w, Boolean dispose)
{
if (w)
{
// If the window is visible, hide it first so
// that the proper activate and deactivate events are sent.
WindowPeek wPeek = (WindowPeek)w;
if (wPeek->visible)
MAHideWindow(w);
if (dispose)
{
if (w == qd.thePort) // Only need to invalidate focus if freed window is the current port
{
if (gApplication)
gApplication->InvalidateFocus();
SetPort(gWorkPort);
}
DisposeWindow(w);
}
else
CloseWindow(w);
}
return NULL; // convenience to caller
} // FreeIfWMgrWindow
//----------------------------------------------------------------------------------------
// GetNewCenteredDialog:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
DialogPtr GetNewCenteredDialog(ResNumber dialogID,
Ptr dStorage,
WindowPtr behind)
{
DialogTHndl dlogTemplate;
SetCursor(&(qd.arrow));
if (gApplication)
gApplication->InvalidateMouseRegions();
dlogTemplate = (DialogTHndl)GetResource('DLOG', dialogID);
if (dlogTemplate)
{
CenterRectOnScreen(((CRect &) (*dlogTemplate)->boundsRect), true, true, true);
return GetNewDialog(dialogID, dStorage, behind);
}
else
{
SysBeep(2); // At least give some indication
#if qDebug
CStr255 theString;
ConcatNumber("Unable to find ‘DLOG’ resource ", dialogID, theString);
ProgramBreak(theString);
#endif
}
return NULL;
} // GetNewCenteredDialog
//----------------------------------------------------------------------------------------
// GetTextStyleFontInfo: Really a utility, but the gWorkPort isn't reachable from
// UMacAppUtilities
//----------------------------------------------------------------------------------------
#pragma segment MAUtilitiesRes
void GetTextStyleFontInfo(const TextStyle& theTextStyle,
FontInfo& theFontInfo,
short& theFontHeight)
{
GrafPtr savedPort;
GetPort(&savedPort);
SetPort(gWorkPort);
SetPortTextStyle(theTextStyle);
theFontHeight = MAGetFontInfo(theFontInfo);
SetPort(savedPort);
} // GetTextStyleFontInfo
//----------------------------------------------------------------------------------------
// DoRealInitToolBox:
//----------------------------------------------------------------------------------------
#pragma push
// Needs to universal code
#pragma processor 68000
#pragma segment MAMiniInit
void DoRealInitToolBox()
{
// -1 == 0xFFFFFFFF, the largest 32 bit address. Our routine StripLong uses a
// pre-stripped address gStrippedAddress to avoid the yucky MPW glue. (NOTE: need
// gStrippedAddress in DefineConfiguration.)
gStrippedAddress = StripAddress((Ptr) - 1);
// Find out just what kind of environment we're dealing with here
DefineConfiguration(gConfiguration);
// Are we background only? If so, bail out...this isn't yet supported by the code.
if (!gConfiguration.isOnlyBackground)
{
// init the toolbox managers
InitGraf(&qd.thePort);
InitFonts();
InitWindows(); // creates non-relocatable for the WM port
// _DON'T_ flush disk-inserted or os events or you'll be sorry!
FlushEvents(everyEvent - diskMask - osMask, 0);
SetEventMask(everyEvent); // allow us to get keyup events too.
InitMenus();
TEInit();
InitDialogs(NULL);
CursHandle aCursHandle = GetCursor(watchCursor); // Watch should be in system
// file, but just in case…
InitCursor();
if (aCursHandle)
SetCursor(*aCursHandle); // Change cursor to watch
// The refnum where the application's resources should be found
gApplicationRefNum = CurResFile();
gToolBoxInitialized = true;
}
else
{
#if qDebug
DebugStr((StringPtr)"\pBackground-only apps not supported");
#endif
ExitToShell();
}
} // DoRealInitToolBox
#pragma pop
extern pascal void _DataInit(); // Routine in the A5 globals initializer
//----------------------------------------------------------------------------------------
// FailedInitToolBox: This procedure is intended to be in "Main" which is already loaded
//----------------------------------------------------------------------------------------
#pragma push
// Needs to universal code
#pragma processor 68000
#pragma segment Main
void FailedInitToolBox()
{
#if qDebug
DebugStr((StringPtr)"\pNot enough room to initialize ToolBox managers");
#endif
ExitToShell();
} // FailedInitToolBox
//----------------------------------------------------------------------------------------
// InitToolBox:
//----------------------------------------------------------------------------------------
void InitToolBox()
{
const short kBreathingRoom = 1024; // Amount of heap space needed for init
Size totalSize = 0;
Size contigSize = 0;
Handle h = NULL;
#if !qPowerPC
// the heap and stack don't overlap. So there's enough room to init the managers. Make
// sure that the MAMiniInit Segment can be loaded and that there's still a little Room
// after that. */
#ifndef __MWERKS__
UnloadSeg(&_DataInit); // Toss some ballast
#endif
// "MAMain" this is MacApp's own code that must be resident even before/ during the
// UMemory startup. GetNamedResource will call RsrvMem which locates the handle as low
// in memory as possible. We will then lock it there just like "Main". In order for
// this to work correctly the build system will have to have set the locked bit on the
// MAMain resource.
#ifndef __MWERKS__
h = GetNamedResource('CODE', "\pMAMain");
#else
h = GetNamedResource('CODE', "\pMain");
#endif
if (h)
HNoPurge(h);
else
FailedInitToolBox();
h = GetNamedResource('CODE', "\pMAMiniInit");
if (h)
HNoPurge(h); // don't let it get squished out of the heap when the grow zone
// might get called below. However, since it is not locked it will
// float up to the top of the heap when it is entered at
// DoRealInitToolBox.
else
FailedInitToolBox();
#endif
// Attempt to ensure that there is going to be kBreathingRoom bytes available in the
// heap so that when the actual toolbox managers are initialized there is a
// significantly reduced chance that they will express their displeasure with us
// through SysErr -25 or -2. If the space is not currently available in the zone as
// shown by PurgeSpace then attempting to allocate it will let growzoneproc operate
// and grow the zone a little, as necessary. If, after that, we haven't been able to
// get the breathing room we desire then just give up and fade silently away. (Like
// the old soldier, not the old executive).
PurgeSpace(&totalSize, &contigSize);
if (totalSize >= kBreathingRoom)
DoRealInitToolBox();
else
{
h = NewHandle(kBreathingRoom);
if (h != NULL) // get the grow space
{
DisposeHandle(h);
DoRealInitToolBox();
}
else
FailedInitToolBox(); // Give up
}
} // InitToolBox
#pragma pop
//----------------------------------------------------------------------------------------
// ValidateConfiguration:
//----------------------------------------------------------------------------------------
#pragma push
// Needs to universal code
#pragma processor 68000
#pragma segment MAMiniInit
Boolean ValidateConfiguration(const Configuration& theConfiguration)
{
Boolean isSupported = true;
// Run the gauntlet of support tests using the conditionally set constants. If any
// single test fails then the app is considered unsupported on this machine.
// Required minimums
isSupported &= theConfiguration.hasROM128K;
isSupported &= theConfiguration.hasScriptManager;
isSupported &= theConfiguration.hasHierarchicalMenus;
isSupported &= theConfiguration.hasStyleTextEdit;
isSupported &= theConfiguration.hasWaitNextEvent;
// Minimum system version
isSupported &= theConfiguration.systemVersion >= 0x605;
// Optionally required
if (qNeedsColorQD)
isSupported &= theConfiguration.hasColorQD;
if (qNeedsMC68020)
isSupported &= ((theConfiguration.processor != gestalt68000) && (theConfiguration.processor != gestalt68010));
if (qNeedsMC68030)
isSupported &= ((theConfiguration.processor != gestalt68000) && (theConfiguration.processor != gestalt68010) && (theConfiguration.processor != gestalt68020));
if (qNeedsMC68040)
isSupported &= ((theConfiguration.processor != gestalt68000) && (theConfiguration.processor != gestalt68010) && (theConfiguration.processor != gestalt68020)
&& (theConfiguration.processor != gestalt68030));
if (qNeedsFPU)
isSupported &= theConfiguration.hasFPU;
// System 7.0 Support
if (qNeedsSystem7)
isSupported &= theConfiguration.systemVersion >= 0x700;
if (qNeedsAppleEventMgr)
isSupported &= theConfiguration.hasAppleEventMgr;
if (qNeedsEditionMgr)
isSupported &= theConfiguration.hasEditionMgr;
if (qNeedsHelpMgr)
isSupported &= theConfiguration.hasHelpMgr;
if (qNeedsAliasMgr)
isSupported &= theConfiguration.hasAliasMgr;
if (qNeedsFolderMgr)
isSupported &= theConfiguration.hasFolderMgr;
if (qNeedsProcessMgr)
isSupported &= theConfiguration.hasProcessMgr;
// skanky hack under A/UX to ensure that all app's are pulled to front early on
if (theConfiguration.hasAUX)
PullApplicationToFront();
return isSupported;
} // ValidateConfiguration
#pragma pop
//----------------------------------------------------------------------------------------
// MAGestaltAttribute:
//----------------------------------------------------------------------------------------
#pragma push
// Needs to universal code
#pragma processor 68000
#pragma segment Main
Boolean MAGestaltAttribute(OSType itsAttr, short itsBit)
{
long response;
return (Gestalt(itsAttr, &response) == noErr) && (((response >> itsBit) & 1) != 0);
} // MAGestaltAttribute
//----------------------------------------------------------------------------------------
// DefineConfiguration:
//----------------------------------------------------------------------------------------
#pragma segment Main
void DefineConfiguration(Configuration& theConfiguration)
{
const short mDesktopBus = 0x0400;
OSErr err;
long response;
err = Gestalt(gestaltVersion, &response);
theConfiguration.environsVersion = (short)response;
err = Gestalt(gestaltMachineType, &response);
theConfiguration.machineType = (short)response;
theConfiguration.hasROM128K = theConfiguration.machineType >= gestaltMac512KE;
if (theConfiguration.hasROM128K)
theConfiguration.hasHFS = true;
else
theConfiguration.hasHFS = LMGetFSFCBLen() > 0;
err = Gestalt(gestaltSystemVersion, &response);
theConfiguration.systemVersion = (short)response;
err = Gestalt(gestaltProcessorType, &response);
theConfiguration.processor = (short)response;
err = Gestalt(gestaltFPUType, &response);
theConfiguration.hasFPU = response != gestaltNoFPU;
err = Gestalt(gestaltQuickdrawVersion, &response);
theConfiguration.hasColorQD = response != gestaltOriginalQD;
err = Gestalt(gestaltQuickdrawVersion, &response);
theConfiguration.has32BitQD = theConfiguration.hasColorQD && (response != gestalt8BitQD);
err = Gestalt(gestaltKeyboardType, &response);
theConfiguration.keyboardType = (short)response;
err = Gestalt(gestaltAppleTalkVersion, &response);
theConfiguration.atDrvrVersNum = (short)response;
theConfiguration.hasSCSI = MAGestaltAttribute(gestaltHardwareAttr, gestaltHasSCSI);
err = Gestalt(gestaltAUXVersion, &response);
theConfiguration.hasAUX = response != 0;
err = Gestalt(gestaltScriptMgrVersion, &response);
theConfiguration.hasScriptManager = theConfiguration.hasROM128K && (response != 0);
theConfiguration.hasTempMem = MAGestaltAttribute(gestaltOSAttr, gestaltTempMemSupport);
err = Gestalt(gestaltTextEditVersion, &response);
theConfiguration.teVersion = response;
theConfiguration.hasDesktopBus = (LMGetHWCfgFlags() & mDesktopBus) > 0;
theConfiguration.hasHierarchicalMenus = theConfiguration.hasROM128K && TrapExists(_PopUpMenuSelect);
theConfiguration.hasStyleTextEdit = theConfiguration.systemVersion >= 0x600;
theConfiguration.hasSoundManager = theConfiguration.hasROM128K && TrapExists(_SndDoCommand);
theConfiguration.hasWaitNextEvent = theConfiguration.hasROM128K && TrapExists(_WaitNextEvent);
// System 7.0 support
theConfiguration.hasAppleEventMgr = MAGestaltAttribute(gestaltAppleEventsAttr, gestaltAppleEventsPresent);
theConfiguration.hasEditionMgr = MAGestaltAttribute(gestaltEditionMgrAttr, gestaltEditionMgrPresent);
theConfiguration.hasHelpMgr = MAGestaltAttribute(gestaltHelpMgrAttr, gestaltHelpMgrPresent);
theConfiguration.hasAliasMgr = MAGestaltAttribute(gestaltAliasMgrAttr, gestaltAliasMgrPresent);
theConfiguration.hasFolderMgr = MAGestaltAttribute(gestaltFindFolderAttr, gestaltFindFolderPresent);
theConfiguration.hasPopupCDEF = MAGestaltAttribute(gestaltPopupAttr, gestaltPopupPresent);
theConfiguration.hasTrueType = MAGestaltAttribute(gestaltFontMgrAttr, gestaltOutlineFonts);
// set default values for Process Manager-related items
theConfiguration.hasProcessMgr = false;
theConfiguration.isOnlyBackground = false;
theConfiguration.isHighLevelEventAware = false;
// ask process mgr for several values
if (MAGestaltAttribute(gestaltOSAttr, gestaltLaunchControl))
{
theConfiguration.hasProcessMgr = true;
ProcessSerialNumber psn;
psn.highLongOfPSN = 0;
psn.lowLongOfPSN = kCurrentProcess;
ProcessInfoRec info;
info.processInfoLength = sizeof(ProcessInfoRec);
info.processName = NULL;
info.processAppSpec = NULL;
if (GetProcessInformation(&psn, &info) == noErr)
{
theConfiguration.isOnlyBackground = (info.processMode & modeOnlyBackground) ? true : false;
theConfiguration.isHighLevelEventAware = (info.processMode & modeHighLevelEventAware) ? true : false;
}
}
theConfiguration.hasDragManager = MAGestaltAttribute('drag', 0);
theConfiguration.hasThreadManager = MAGestaltAttribute('thds', 0);
theConfiguration.hasAOCEToolBox = MAGestaltAttribute('oceu', 0);
theConfiguration.hasQDGXGraphics = MAGestaltAttribute('grfx', 0);
theConfiguration.hasQDGXPrinting = MAGestaltAttribute('pmgr', 0);
theConfiguration.hasASLM = MAGestaltAttribute('aslm', 0);
theConfiguration.hasCFM = MAGestaltAttribute(gestaltCFMAttr, gestaltCFMPresent);
theConfiguration.hasTranslationManager = MAGestaltAttribute(gestaltTranslationAttr, gestaltTranslationMgrExists);
theConfiguration.hasSpeechManager = MAGestaltAttribute(gestaltSpeechAttr, gestaltSpeechMgrPresent);
theConfiguration.hasCustomFile = MAGestaltAttribute(gestaltStandardFileAttr, gestaltStandardFile58);
theConfiguration.hasQuickTime = (Gestalt(gestaltQuickTime, &response) == noErr);
theConfiguration.hasTSM = (Gestalt(gestaltTSMgrVersion, &response) == noErr);
} // DefineConfiguration
#pragma pop
//----------------------------------------------------------------------------------------
// ClearTheFPU: Essential one-time initialization
//
// INLINE 0x42A7, // CLR.L -(A7)
// 0x42A7, // CLR.L -(A7)
// 0xF21F, 0x9800; // FMOVEM (A7)+, FPCR/FPSR
//----------------------------------------------------------------------------------------
#if !qPowerPC
void ClearTheFPU() = { 0x42A7, 0x42A7, 0xF21F, 0x9800 };
#endif
//----------------------------------------------------------------------------------------
// InitUMacApp_Step1 and InitUMacApp_Step3
//----------------------------------------------------------------------------------------
#pragma push
#pragma processor 68000
// Needs to be universal code
#pragma segment Main
// Must be in the Main segment since all other segments get unloaded from here.
void InitUMacApp_Step1()
{
if (!gToolBoxInitialized)
InitToolBox();
// Init the basics used by the ErrorMgr (we need this for StdAlert
// in case ValidateConfiguration fails)
gMacAppAlertFilter = (ProcPtr) & MacAppAlertFilter;
if (ValidateConfiguration(gConfiguration)) // Make sure we can run. The programmer
// really should have ensured this in
// their "M" file but this is a backup
// check just in case. After all 68000's
// don't really like to RTD.
{
#if !qPowerPC
// the main procedure is always compiled with universal code so, the FPU must be
// reset before it is used. We could get spurious crashes or worse. Remember:
// 2+2=4 every time!
if (qNeedsFPU || gConfiguration.hasFPU)
ClearTheFPU();
#endif
}
else
{
StdAlert(phUnsupportedConfiguration);
ExitToShell(); // leave the application pronto!
}
} // InitUMacApp_Step1
//----------------------------------------------------------------------------------------
void InitUMacApp_Step3(short callsToMoreMasters)
{
// Install MacApp's Memory management system
InitUMemory(callsToMoreMasters);
#if !qPowerPC
UnloadAllSegments();
// Force the init segment to be memory resident, so we can call UnloadAllSegs
// during init
short initSeg = GetSegNumber((ProcPtr) & DoInitUMacApp);
#ifdef __MWERKS__
//CW can't set up the jump table if if it has already been set up. If it's locked
//then it's set up.
{
Handle seg;
Handle GetSegResource(short segnum);
seg = GetSegResource(initSeg);
if (IsHandleLocked(seg)) // not yet locked
(*gIsResidentSeg)[initSeg - 1] = true;
else
SetResidentSegment(initSeg, true);
}
#else
SetResidentSegment(initSeg, true);
#endif
#endif
DoInitUMacApp(); // do rest of initialization
#if !qPowerPC
SetResidentSegment(initSeg, false); // make it non-resident
UnloadAllSegments();
#endif
} // InitUMacApp_Step3
#pragma pop
//----------------------------------------------------------------------------------------
// DoInitUMacApp: Must be in the init segment; unloaded at start of event loop
//----------------------------------------------------------------------------------------
#pragma segment MAInit
void DoInitUMacApp()
{
// Initialize runtime support for objects
InitUObject();
#if qDebug || qTheDebugger
InitUDebug();
#endif
gOrthogonal[vSel] = hSel;
gOrthogonal[hSel] = vSel;
gErrorParm3 = "";
// assign the global text style records from resources
MAGetTextStyle(kSystemFontTextStyle, gSystemStyle);
MAGetTextStyle(kApplFont12TextStyle, gApplicationStyle);
MAGetTextStyle(kApplFont9TextStyle, gApplicationStyle9);
// atexit(&CleanupMacApp);
pETSPatch.Install(ExitToShellCleanupMacApp);
// Other 1-time initialization
gTemporaryRegion = MakeNewRgn();
// Create a work port for our convenience
if (qNeedsColorQD || gConfiguration.hasColorQD)
gWorkPort = NewCWindow(NULL, gZeroRect, gEmptyString, false, documentProc, NULL, false, 0);
else
gWorkPort = NewWindow(NULL, gZeroRect, gEmptyString, false, documentProc, NULL, false, 0);
{
CRect theGrayRect((*GetGrayRgn())->rgnBBox);
gStandardWindowMoveBounds = theGrayRect;
gStandardWindowMoveBounds.Inset(CPoint(4, 4));
// arbitrary minimum size; maximum size is grayRgn size minus half the title bar
gStandardWindowSizeRect = CRect(CPoint(80, 80), theGrayRect.GetSize());
gStandardWindowSizeRect.bottom -= 8;
gStandardWindowScreenRect = theGrayRect;
gStandardWindowScreenRect.Inset(CPoint(16, 16));
}
InitUBusyCursor();
gNullPrintHandler = new TPrintHandler;
gNullPrintHandler->IPrintHandler(NULL);
gPrintHandler = gNullPrintHandler;
// Create the signature lists.
gSignatures = new TDynamicArray;
gSignatures->IDynamicArray(kEmptyIndex, sizeof(SignatureRec));
if (qTemplateViews)
{
// ===============================================
// Suppress Linker dead stripping of these classes
macroDontDeadStrip(TView);
macroDontDeadStrip(TIncludeView);
macroDontDeadStrip(TWindow);
macroDontDeadStrip(TScrollBar);
macroDontDeadStrip(TScrollerScrollBar);
macroDontDeadStrip(TScroller);
macroDontDeadStrip(TTracker);
macroDontDeadStrip(TList);
// ===============================================
RegisterStdType("TView", kStdView);
RegisterStdType("TView", kStdDefaultView);
RegisterStdType("TIncludeView", kStdIncludeAt);
RegisterStdType("TWindow", kStdWindow);
RegisterStdType("TScrollBar", kStdScrollBar);
RegisterStdType("TScrollerScrollBar", kStdScrollerScrollBar);
RegisterStdType("TScroller", kStdScroller);
RegisterStdType("TTracker", kStdTracker);
RegisterStdType("TList", kStdList);
}
#if qDebug
// The linker optimizes away the meta information for the following classes by
// stripping the ClassInfoProc. MacApp does a SetEltType on lists containing these
// classes which requires meta information. Suppress the optimization by doing
// suppressing dead stripping. (See UApplication.cp)
macroDontDeadStrip(TDocument);
macroDontDeadStrip(TEvent);
macroDontDeadStrip(TClientCommand);
#endif
InitUAdorners(); // Temporarily needed for debug window
InitUMenuMgr();
InitUClipboardMgr();
InitUAppleEvents();
// create gServerAddress
if (qNeedsAppleEventMgr || gConfiguration.hasAppleEventMgr)
{
ProcessSerialNumber psn;
psn.highLongOfPSN = 0;
psn.lowLongOfPSN = kCurrentProcess;
FailOSErr(AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &gServerAddress));
}
// initialize the pseudo-random sequence generation function
unsigned long time;
GetDateTime(&time);
srand((unsigned int)time);
#if qDebug
InitUDialog();
#endif
} // DoInitUMacApp
//----------------------------------------------------------------------------------------
// InstallIfPrintHandler:
//----------------------------------------------------------------------------------------
#pragma segment MARes
void InstallIfPrintHandler(TPrintHandler* aPrintHandler,
TView* aView)
{
TPrintHandler * aNewPrintHandler;
if ((aPrintHandler) && (aView) && (aPrintHandler != gNullPrintHandler) && (gPrintHandler != gNullPrintHandler))
{
aNewPrintHandler = (TPrintHandler *)aPrintHandler->Clone();// signals failure if can't clone
aNewPrintHandler->fView = aView;
aNewPrintHandler->SetDefaultPrintInfo();
if (aView->fDocument)
aView->fDocument->AttachPrintHandler(aNewPrintHandler);
aView->AttachPrintHandler(aNewPrintHandler);
}
} // InstallIfPrintHandler
//----------------------------------------------------------------------------------------
// MakeNewRgn:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
RgnHandle MakeNewRgn()
{
RgnHandle aRgn = NewRgn();
FailNIL(aRgn);
return aRgn;
} // MakeNewRgn
//----------------------------------------------------------------------------------------
// DetermineClassDesc:
//----------------------------------------------------------------------------------------
#pragma segment MAOpen
const ClassDesc* DetermineClassDesc(IDType signature, const ClassName& className)
{
if (className.IsEmpty())
return GetClassDescFromSignature(signature);
else
return ClassDesc::GetClassDescFromClassName(className);
} // DetermineClassDesc
//----------------------------------------------------------------------------------------
// GetClassDescFromSignature:
//----------------------------------------------------------------------------------------
#pragma segment MAOpen
const ClassDesc* GetClassDescFromSignature(IDType signature)
{
CArrayIterator iter(gSignatures);
for (ArrayIndex i = iter.FirstIndex(); iter.More(); i = iter.NextIndex())
{
SignatureRecPtr aSignaturePtr = (SignatureRecPtr)gSignatures->ComputeAddress(i);
if (aSignaturePtr->itsSignature == signature)
return aSignaturePtr->itsClassDesc;
}
return NULL;
} // GetClassDescFromSignature
//----------------------------------------------------------------------------------------
// NewStdObject:
//----------------------------------------------------------------------------------------
#pragma segment MAOpen
TObject* NewStdObject(IDType signature)
{
const ClassDesc* classDesc = GetClassDescFromSignature(signature);
if (classDesc != NULL)
return (TObject*)(classDesc->Call_DefaultConstructor());
else
{
#if qDebug
fprintf(stderr, "signature=‘%4s’\n", (char*) & signature);
ProgramBreak("Unable to find class for the given signature");
#endif
Failure(errMissingSignature, 0);
return NULL; // this statement is never executed, but defeats an xlC warning
}
} // NewStdObject
//----------------------------------------------------------------------------------------
// NewObjectBySignature:
//----------------------------------------------------------------------------------------
#pragma segment MAOpen
TObject* NewObjectBySignature(IDType signature,
const ClassName& className)
{
if (className.IsEmpty())
return NewStdObject(signature);
else
return ClassDesc::NewByClassName(className);
} // NewObjectBySignature
//----------------------------------------------------------------------------------------
// FindPos:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
short FindPos(const CStr255& pattern, CStr255& source)
{
short i = 0;
short j = 0;
short position = 0;
do
{
++i;
position = i;
for (j = 1; j <= pattern.Length(); ++j)
if (!((source[i + j - 1] == pattern[j]) && (CharByte((Ptr) & source, i + j) == 0)))
{
position = 0;
break;
}
} while (!((position > 0) || (i >= source.Length() - pattern.Length() + 1)));
return position;
} // FindPos
//----------------------------------------------------------------------------------------
// ParseTitleTemplate:
//----------------------------------------------------------------------------------------
Boolean ParseTitleTemplate(CStr255& itsTemplate,
short& preDocname,
short& constTitle)
{
const CStr255 kPreDocname = "<<<";
const short kPreSize = 3;
const CStr255 kPostDocname = ">>>";
const short kPostSize = 3;
if (itsTemplate.IsEmpty())
{
preDocname = 1;
constTitle = 0;
}
else
{
preDocname = FindPos(kPreDocname, itsTemplate);
if (preDocname > 0)
{
itsTemplate.Delete(preDocname, kPreSize);
short x = FindPos(kPostDocname, itsTemplate);
if (x == 0)
constTitle = preDocname - 1;
else
{
itsTemplate.Delete(x, kPostSize);
constTitle = itsTemplate.Length() - x + preDocname;
}
}
}
return preDocname > 0;
} // ParseTitleTemplate
//----------------------------------------------------------------------------------------
// RegisterStdType: Register or re-register a type and a class
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
void RegisterStdType(const CStr255& typeName,
IDType signature)
{
CArrayIterator iter(gSignatures);
SignatureRec itsSignatureRec;
// If the name can't be found it was probably misspelled or dead-stripped
itsSignatureRec.itsSignature = signature;
itsSignatureRec.itsClassDesc = ClassDesc::GetClassDescFromClassName(typeName);
if (itsSignatureRec.itsClassDesc == NULL)
Failure(minErr, 0);
// Replace or add signature as necessary
for (ArrayIndex i = iter.FirstIndex(); iter.More(); i = iter.NextIndex())
if (((SignatureRecPtr)(gSignatures->ComputeAddress(i)))->itsSignature == signature)
break;
if (iter.More())
*((SignatureRecPtr)(gSignatures->ComputeAddress(i))) = itsSignatureRec;
else
gSignatures->InsertElementsBefore(gSignatures->GetSize() + 1, &itsSignatureRec, 1);
} // RegisterStdType
//----------------------------------------------------------------------------------------
// GetStandardType:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
IDType GetStandardType(const ClassDesc* itsClassDesc)
{
if (itsClassDesc != NULL)
{
CArrayIterator iter(gSignatures);
// find signature
for (ArrayIndex i = iter.FirstIndex(); iter.More(); i = iter.NextIndex())
if (((SignatureRecPtr)(gSignatures->ComputeAddress(i)))->itsClassDesc == itsClassDesc)
return ((SignatureRecPtr)(gSignatures->ComputeAddress(i)))->itsSignature;
}
// if we get here, the class descriptor wasn't found in the table of standard signatures
return kNoIdentifier;
} // GetStandardType
//----------------------------------------------------------------------------------------
// SubstituteInTitle:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
Boolean SubstituteInTitle(CStr255& title,
const CStr255& newStuff,
short preDocname,
short constTitle)
{
if (preDocname > 0)
{
if (constTitle == 0)
title = newStuff;
else
{
title.Delete(preDocname, title.Length() - constTitle);
title.Insert(newStuff, preDocname);
}
return true;
}
else
return false;
} // SubstituteInTitle
//----------------------------------------------------------------------------------------
// UseTemporaryRegion: Call this when you are about to use gTemporaryRegion and qDebug is
// true. Used with DoneWithTemporaryRegion will prevent you from trying to use
// gTemporaryRegion from two places at the same time.
//----------------------------------------------------------------------------------------
#if qDebug
#pragma segment MADebug
void UseTemporaryRegion(const CStr255& byWhom)
{
if (gBusyTemporaryRegion)
{
fprintf(stderr, "‘%s’ is trying to lock gTemporaryRegion,", (char*)byWhom);
fprintf(stderr, "but it is already locked by ‘%s’\n", (char*)gUsedBy);
ProgramBreak("Error in UseTemporaryRegion");
}
else
{
gBusyTemporaryRegion = true;
gUsedBy = byWhom;
}
} // UseTemporaryRegion
#endif
//========================================================================================
// CLASS CTemporaryRegion
//========================================================================================
#undef Inherited
//----------------------------------------------------------------------------------------
// CTemporaryRegion::new:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
void* CTemporaryRegion::operator new(size_t size)
{
return ::operator new(size);
}
//----------------------------------------------------------------------------------------
// CTemporaryRegion::delete:
//----------------------------------------------------------------------------------------
#pragma segment IteratorRes
void CTemporaryRegion::operator delete(void*)
{
}
//----------------------------------------------------------------------------------------
// CTemporaryRegion::CTemporaryRegion:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
CTemporaryRegion::CTemporaryRegion()
{
// Simple single level cache for first cut
// take the cached region if available otherwise make one up to give out
if (fCachedRgn)
{
fRgnHandle = fCachedRgn;
fCachedRgn = NULL;
}
else
{
fRgnHandle = MakeNewRgn();
}
// Setup the FailInfo to catch any failures while this object is in scope
fFailInfo.Reset(); // ensure that fFailInfo is in an initial state
fFailInfo.SetCleanupProc(CTemporaryRegion::CallCleanup, this);
} // CTemporaryRegion::CTemporaryRegion
//----------------------------------------------------------------------------------------
// CTemporaryRegion::~CTemporaryRegion:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
CTemporaryRegion::~CTemporaryRegion()
{
this->Cleanup();
Success(fFailInfo);
} // CTemporaryRegion::~CTemporaryRegion
//----------------------------------------------------------------------------------------
// CTemporaryRegion::Cleanup:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
void CTemporaryRegion::Cleanup()
{
// return to the cache if not already full
if (fCachedRgn)
{
fRgnHandle = DisposeIfRgnHandle(fRgnHandle);
}
else
{
fCachedRgn = fRgnHandle;
fRgnHandle = NULL;
}
} // CTemporaryRegion::Cleanup
//----------------------------------------------------------------------------------------
// CTemporaryRegion::CallCleanup:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
/*static*/ void CTemporaryRegion::CallCleanup(void* context)
{
((CTemporaryRegion*) context)->Cleanup();
} // CTemporaryRegion::CallCleanup
//========================================================================================
// GLOBAL Procedures
//========================================================================================
#undef Inherited
//----------------------------------------------------------------------------------------
// FindProcessBySignature:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
OSErr FindProcessBySignature(OSType sig,
ProcessSerialNumber& psn,
FSSpec* fileSpec)
{
OSErr err;
ProcessInfoRec info;
psn.highLongOfPSN = 0;
psn.lowLongOfPSN = kNoProcess;
do
{
err= GetNextProcess(&psn);
if( err == noErr )
{
info.processInfoLength = sizeof(ProcessInfoRec);
info.processName = NULL;
info.processAppSpec = fileSpec;
err= GetProcessInformation(&psn, &info);
}
} while( (err == noErr) && info.processSignature != sig );
if( err == noErr )
psn = info.processNumber;
return err;
} // FindProcessBySignature
//----------------------------------------------------------------------------------------
// GetSysVolume:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
OSErr GetSysVolume(short& vRefNum)
{
OSErr theErr;
if (qNeedsFolderMgr || gConfiguration.hasFolderMgr)
{
long dir;
theErr = FindFolder(kOnSystemDisk, kSystemFolderType, false, &vRefNum, &dir);
}
else
{
SysEnvRec environment;
theErr = SysEnvirons(1, &environment);
vRefNum = environment.sysVRefNum;
}
return theErr;
} // GetSysVolume
//----------------------------------------------------------------------------------------
// GetIndVolume:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
OSErr GetIndVolume(short index,
short& vRefNum)
{
ParamBlockRec pb;
OSErr err;
pb.volumeParam.ioCompletion = NULL;
pb.volumeParam.ioNamePtr = NULL;
pb.volumeParam.ioVolIndex = index;
err = PBGetVInfo(&pb, false);
vRefNum = pb.volumeParam.ioVRefNum;
return err;
} // GetIndVolume
//----------------------------------------------------------------------------------------
// VolHasDesktopDB:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
OSErr VolHasDesktopDB(short vRefNum, Boolean& hasDesktop)
{
HParamBlockRec pb;
GetVolParmsInfoBuffer info;
pb.ioParam.ioCompletion = NULL;
pb.ioParam.ioVRefNum = vRefNum;
pb.ioParam.ioNamePtr = NULL;
pb.ioParam.ioBuffer = (Ptr) & info;
pb.ioParam.ioReqCount = sizeof(GetVolParmsInfoBuffer);
OSErr err = ::PBHGetVolParmsSync(&pb);
hasDesktop = (err == noErr) && ((info.vMAttrib & (1L << bHasDesktopMgr)) != 0);
return err;
} // VolHasDesktopDB
//----------------------------------------------------------------------------------------
// FindAppOnVolume:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
OSErr FindAppOnVolume(OSType sig,
short vRefNum,
FSSpec& thefile)
{
DTPBRec pb;
OSErr err;
pb.ioCompletion = NULL;
pb.ioVRefNum = vRefNum;
pb.ioNamePtr = NULL;
if ((err = PBDTGetPath(&pb)) != noErr)
return err; // Puts DT refnum into pb.ioDTRefNum
short refNum = pb.ioDTRefNum;
pb.ioCompletion = NULL;
pb.ioDTRefNum = refNum;
pb.ioIndex = 0;
pb.ioFileCreator = sig;
pb.ioNamePtr = (StringPtr) thefile.name;
err = PBDTGetAPPLSync(&pb); // Find it!
if( err == fnfErr )
err = afpItemNotFound; // Bug in PBDTGetAPPL
if( err )
return err; // Returns afpItemNotFound if app wasn't found.
thefile.vRefNum = vRefNum;
thefile.parID = pb.ioAPPLParID;
return err;
} // FindAppOnVolume
//----------------------------------------------------------------------------------------
// LaunchAppByFSSpec:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
OSErr LaunchAppByFSSpec(const FSSpec& fileSpec,
LaunchFlags launchControlFlags,
ProcessSerialNumber& psn)
{
LaunchParamBlockRec pb;
OSErr err;
FSSpec localFSSpec = fileSpec; // so we can take its address below
pb.launchBlockID = extendedBlock;
pb.launchEPBLength = extendedBlockLen;
pb.launchFileFlags = launchNoFileFlags;
pb.launchControlFlags = launchControlFlags | launchNoFileFlags;
pb.launchAppSpec = &localFSSpec;
pb.launchAppParameters = NULL;
err = LaunchApplication(&pb);
if (err == noErr)
psn = pb.launchProcessSN;
return err;
} // LaunchAppByFSSpec
//----------------------------------------------------------------------------------------
// LaunchBySignature:
//----------------------------------------------------------------------------------------
#pragma segment MAGlobalsRes
OSErr LaunchBySignature(OSType sig,
ProcessSerialNumber& psn,
FSSpec* fileSpec,
Boolean* launched,
Boolean allowLaunch,
LaunchFlags launchControlFlags)
{
OSErr err;
short sysVRefNum;
// First see if it's already running:
if (launched)
*launched = false;
err = FindProcessBySignature(sig, psn, fileSpec);
if (err == noErr)
if ((launchControlFlags & launchDontSwitch) == 0)
return SetFrontProcess(&psn); // They wanted to switch to it…
if (err != procNotFound || !allowLaunch)
return err;
// Well, it's not running but it's okay to launch it. Let's have a look around:
if ((err = GetSysVolume(sysVRefNum)) != noErr)
return err; // Find boot volume
short vRefNum = sysVRefNum; // Start search with boot volume
short index = 0;
do
{
if (index == 0 || vRefNum != sysVRefNum)
{
Boolean hasDesktopDB;
if ((err = VolHasDesktopDB(vRefNum, hasDesktopDB)) != noErr)
return err;
if (hasDesktopDB)
{
FSSpec file;
// If volume has a desktop DB,
err = FindAppOnVolume(sig, vRefNum, file); // ask it to find app
if (err == noErr)
{
// If found,
if (fileSpec)
*fileSpec = file;
if (launched)
*launched = true;
return LaunchAppByFSSpec(file, launchControlFlags, psn); // Launch it!
}
else if (err != afpItemNotFound)
return err;
}
}
err = GetIndVolume(++index, vRefNum); // Else go to next volume
} while (err == noErr); // Keep going until we run out of vols
if( err==nsvErr || err==afpItemNotFound )
err= fnfErr; // File not found on any volume
return err;
} // LaunchBySignature