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:
Text File  |  1994-09-17  |  54.1 KB  |  1,910 lines  |  [TEXT/MPS ]

  1. /*
  2. *    This file has been changed from the original MacApp 3.1.1
  3. *    to support the metrowerks CodeWarrior compilers C/C++ 1.1.1.
  4. *    These changes are known *not* to work with earlier versions
  5. *    of CodeWarrior.  Every attempt though has been made to to keep 
  6. *    this file compatible with other development environments.
  7. *
  8. *    Mark Anderson
  9. *    metrowerks
  10. *    9/16/94
  11. *
  12. */
  13.  
  14. //----------------------------------------------------------------------------------------
  15. // UMacAppGlobals.cp 
  16. // Copyright © 1984-1994 by Apple Computer Inc. All rights reserved.
  17. //----------------------------------------------------------------------------------------
  18.  
  19. #ifndef __UMACAPPGLOBALS__
  20. #include "UMacAppGlobals.h"
  21. #endif
  22.  
  23. #ifndef __ULIST__
  24. #include <UList.h>
  25. #endif
  26.  
  27. #ifndef __APPLEEVENTS__
  28. #include <AppleEvents.h>
  29. #endif
  30.  
  31. #ifndef __EDITIONS__
  32. #include <Editions.h>
  33. #endif
  34.  
  35. #ifndef __UAPPLEEVENTS__
  36. #include <UAppleEvents.h>
  37. #endif
  38.  
  39. #ifndef __UEVENT__
  40. #include <UEvent.h>
  41. #endif
  42.  
  43. #ifndef __UCOMMAND__
  44. #include <UCommand.h>
  45. #endif
  46.  
  47. #ifndef __UDESIGNATOR__
  48. #include <UDesignator.h>
  49. #endif
  50.  
  51. #ifndef __UEVENTHANDLER__
  52. #include <UEventHandler.h>
  53. #endif
  54.  
  55. #ifndef __UAPPLICATION__
  56. #include <UApplication.h>
  57. #endif
  58.  
  59. #ifndef __UDOCUMENT__
  60. #include <UDocument.h>
  61. #endif
  62.  
  63. #ifndef __UFILEBASEDDOCUMENT__
  64. #include <UFileBasedDocument.h>
  65. #endif
  66.  
  67. #ifndef __UPRINTHANDLER__
  68. #include <UPrintHandler.h>
  69. #endif
  70.  
  71. #ifndef __BALLOONS__
  72. #include <Balloons.h>
  73. #endif
  74.  
  75. #ifndef __UVIEW__
  76. #include <UView.h>
  77. #endif
  78.  
  79. #ifndef __USTREAM__
  80. #include <UStream.h>
  81. #endif
  82.  
  83. #ifndef __UADORNERS__
  84. #include <UAdorners.h>
  85. #endif
  86.  
  87. #ifndef __UWINDOW__
  88. #include <UWindow.h>
  89. #endif
  90.  
  91. #ifndef __CONTROLS__
  92. #include <Controls.h>
  93. #endif
  94.  
  95. #ifndef __UCONTROL__
  96. #include <UControl.h>
  97. #endif
  98.  
  99. #ifndef __USCROLLER__
  100. #include <UScroller.h>
  101. #endif
  102.  
  103. #ifndef __UMACAPPUTILITIES__
  104. #include <UMacAppUtilities.h>
  105. #endif
  106.  
  107. #ifndef __UERRORMGR__
  108. #include <UErrorMgr.h>
  109. #endif
  110.  
  111. #ifndef __UMEMORY__
  112. #include <UMemory.h>
  113. #endif
  114.  
  115. #ifndef __ERRORS__
  116. #include <Errors.h>
  117. #endif
  118.  
  119. #ifndef __TOOLUTILS__
  120. #include <ToolUtils.h>
  121. #endif
  122.  
  123. #ifndef __UBUSYCURSOR__
  124. #include <UBusyCursor.h>
  125. #endif
  126.  
  127. #ifndef __UDEBUG__
  128. #include <UDebug.h>
  129. #endif
  130.  
  131. #ifndef __UDEPENDENCIES__
  132. #include <UDependencies.h>
  133. #endif
  134.  
  135. #ifndef __MENUS__
  136. #include <Menus.h>
  137. #endif
  138.  
  139. #ifndef __UMENUMGR__
  140. #include <UMenuMgr.h>
  141. #endif
  142.  
  143. #ifndef __SCRAP__
  144. #include <Scrap.h>
  145. #endif
  146.  
  147. #ifndef __UCLIPBOARDMGR__
  148. #include <UClipboardMgr.h>
  149. #endif
  150.  
  151. #ifndef __UDESKSCRAPVIEW__
  152. #include <UDeskScrapView.h>
  153. #endif
  154.  
  155. #ifndef __USYNCHSCROLLER__
  156. #include <USynchScroller.h>
  157. #endif
  158.  
  159. #ifndef __RESOURCES__
  160. #include <Resources.h>
  161. #endif
  162.  
  163. #ifndef __FONTS__
  164. #include <Fonts.h>
  165. #endif
  166.  
  167. #ifndef __PACKAGES__
  168. #include <Packages.h>
  169. #endif
  170.  
  171. #ifndef __SCRIPT__
  172. #include <Script.h>
  173. #endif
  174.  
  175. #ifndef __DEVICES__
  176. #include <Devices.h>
  177. #endif
  178.  
  179. #ifndef __STDIO__
  180. #include <stdio.h>
  181. #endif
  182.  
  183. #ifndef __FOLDERS__
  184. #include <Folders.h>
  185. #endif
  186.  
  187. #ifndef __OSEVENTS__
  188. #include <OSEvents.h>
  189. #endif
  190.  
  191. #ifndef __GESTALTEQU__
  192. #include <GestaltEqu.h>
  193. #endif
  194.  
  195. #ifndef __PROCESSES__
  196. #include <Processes.h>
  197. #endif
  198.  
  199. #ifndef __STDLIB__
  200. #include <stdlib.h>
  201. #endif
  202.  
  203. #ifndef __LOWMEM__
  204. #include <LowMem.h>
  205. #endif
  206.  
  207. //----------------------------------------------------------------------------------------
  208. #if qPowerPC && !defined(__MWERKS__)
  209. QDGlobals qd;
  210. #endif
  211.  
  212. Boolean gCouldPrint;
  213.  
  214. TDynamicArray* gSignatures;
  215.  
  216. TextStyle gSystemStyle;
  217. TextStyle gApplicationStyle;
  218. TextStyle gApplicationStyle9;
  219.  
  220. WindowPtr gWorkPort;
  221.  
  222. RgnHandle gTemporaryRegion = NULL;
  223.  
  224. RgnHandle CTemporaryRegion::fCachedRgn = NULL;
  225.  
  226. NMRecPtr gNotificationPtr = NULL;
  227.  
  228. ModalFilterYDProcPtr gModalFilterYDProcPtr = MacAppStandardFileFilter;
  229.     
  230. #if qDebug
  231. Boolean gBusyTemporaryRegion = false;
  232. CStr255 gUsedBy = "";
  233. #endif
  234.  
  235. FailInfo pFi;
  236.  
  237. //========================================================================================
  238. // CLASS PatchExitToShell
  239. //========================================================================================
  240. #pragma segment MAGlobalsRes
  241.  
  242. typedef pascal void (*ExitToShellType)(void);
  243.  
  244. enum
  245. {
  246.     uppExitToShellProcInfo = kPascalStackBased
  247. };
  248.  
  249. #if USESROUTINEDESCRIPTORS
  250. typedef UniversalProcPtr ExitToShellUPP;
  251.  
  252. #define CallExitToShellProc(userRoutine)        \
  253.         CallUniversalProc((UniversalProcPtr)(userRoutine), uppExitToShellProcInfo)
  254. #define NewExitToShellProc(userRoutine)  \
  255.         (ExitToShellUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppExitToShellProcInfo, GetCurrentISA())
  256. #else
  257. typedef ProcPtr ExitToShellUPP;
  258.  
  259. #define CallExitToShellProc(userRoutine)        \
  260.         (*(userRoutine))()
  261. #define NewExitToShellProc(userRoutine)        \
  262.         (ExitToShellUPP)(userRoutine)
  263. #endif
  264.     
  265. class PatchExitToShell : public TrapPatch
  266. {
  267.   public:
  268.     void Install(ExitToShellType routine);
  269.     void CallInherited(void);
  270. };
  271.  
  272. //--------------------------------------------------------------------------------------------------
  273. #pragma segment MAInit
  274.  
  275. void PatchExitToShell::Install(ExitToShellType routine)
  276. {
  277.     patchRoutine = NewExitToShellProc(StripLong(routine));
  278.     FailNIL(patchRoutine);
  279.     PatchTrap(_ExitToShell, patchRoutine);
  280. }
  281.  
  282. //--------------------------------------------------------------------------------------------------
  283. #pragma segment MAGlobalsRes
  284.  
  285. void PatchExitToShell::CallInherited(void)
  286. {
  287.     CallExitToShellProc((ExitToShellType) oldTrapAddr);
  288. }
  289.  
  290. //--------------------------------------------------------------------------------------------------
  291.  
  292. PatchExitToShell pETSPatch;
  293.  
  294. //========================================================================================
  295. // GLOBAL Functions
  296. //========================================================================================
  297.  
  298. //----------------------------------------------------------------------------------------
  299. // GetAlertButtonTitle: Retrieve the title of the button control. If itemNo isn't a
  300. // button, then return ''.
  301. //----------------------------------------------------------------------------------------
  302. #pragma segment MAGlobalsRes
  303.  
  304. void GetAlertButtonTitle(DialogPtr theDialog,
  305.                          short itemNo,
  306.                          CStr255& theTitle)
  307. {
  308.     short itemType;
  309.     Handle item;
  310.     Rect box;
  311.  
  312.     theTitle = "";
  313.     GetDialogItem(theDialog, itemNo, &itemType, &item, &box);
  314.     if (itemType == (ctrlItem + btnCtrl))
  315.         GetControlTitle((ControlHandle)item, theTitle);
  316. } // GetAlertButtonTitle 
  317.  
  318. //----------------------------------------------------------------------------------------
  319. // DoAlertKeyDown: Handle a keypress that has been mapped to one of the button controls.
  320. //----------------------------------------------------------------------------------------
  321. #pragma segment MAGlobalsRes
  322.  
  323. void DoAlertKeyDown(DialogPtr theDialog, short itemNo)
  324. {
  325.     short itemType;
  326.     Handle item;
  327.     Rect box;
  328.     long finalTicks;
  329.  
  330.     GetDialogItem(theDialog, itemNo, &itemType, &item, &box);
  331.     if (itemType == (ctrlItem + btnCtrl))
  332.     {
  333.         // this code gives visual feedback 
  334.         HiliteControl((ControlHandle)item, inButton);    // hilite the button 
  335.         Delay(8, &finalTicks);                            // delay for 8 ticks 
  336.         HiliteControl((ControlHandle)item, 0);            // stop hiliting the button 
  337.     }
  338. } // DoAlertKeyDown 
  339.  
  340. //----------------------------------------------------------------------------------------
  341. // CompareAlertKeysToItem: Compares the buffered multi-byte chars to the first character
  342. // of each button title 1st button in alert (by convention == "OK"). 2nd button in alert
  343. // (by convention == "Cancel"). 3rd button in alert (by convention == "No")
  344. //----------------------------------------------------------------------------------------
  345. #pragma segment MAGlobalsRes
  346.  
  347. Boolean CompareAlertKeysToItem(DialogPtr theDialog,
  348.                                CStr31& theChars,
  349.                                short& itemHit)
  350. {
  351.     CStr255 title;
  352.  
  353.     GetAlertButtonTitle(theDialog, ok, title);
  354.     if (CompareMultiByteChars(theChars, title, false))
  355.     {
  356.         itemHit = ok;
  357.         return true;
  358.     }
  359.  
  360.     GetAlertButtonTitle(theDialog, cancel, title);
  361.     if (CompareMultiByteChars(theChars, title, false))
  362.     {
  363.         itemHit = cancel;
  364.         return true;
  365.     }
  366.  
  367.     GetAlertButtonTitle(theDialog, kNoButton, title);
  368.     if (CompareMultiByteChars(theChars, title, false))
  369.     {
  370.         itemHit = kNoButton;
  371.         return true;
  372.     }
  373.     return false;
  374. } // CompareAlertKeysToItem 
  375.  
  376. //----------------------------------------------------------------------------------------
  377. // DrawDefaultProc:  Draw the thick rounded rectangle around the default button
  378. // (Imported to MacApp from Ponnuki by GA)
  379. //
  380. // This routine uses Keith Rollin's algorithm, as presented in the USENET Guide to
  381. // Programming the Macintosh. I have modified the basic algorithm only slightly--I add
  382. // two to the calculated 'buttonOval' value. This gets better results, particularly for
  383. // buttons of the default size (18 points).
  384. //----------------------------------------------------------------------------------------
  385. #pragma segment MAGlobalsRes
  386.  
  387. void DrawDefaultProc(DialogPtr dlog)
  388. {
  389.     short                defaultButton;
  390.     
  391.     // Don't call GetDialogItem if the default button # has a strange value
  392.     defaultButton = ((DialogPeek)dlog)->aDefItem;
  393.     if( defaultButton > 0 )
  394.     {
  395.         GrafPtr                savePort;
  396.         short                type = 0;
  397.         ControlHandle        buttonHandle = NULL;
  398.         CRect                outlineBox;
  399.  
  400.         GetPort(&savePort);
  401.         SetPort( dlog );
  402.  
  403.         GetDialogItem(dlog, defaultButton, &type, (Handle *) &buttonHandle, outlineBox);
  404.         InsetRect(outlineBox,-4,-4);
  405.  
  406.         // Don't draw the bold outline around the default button
  407.         // unless it really is a button
  408.         if( type == ctrlItem + btnCtrl )
  409.         {
  410.             PenState            saveState;
  411.             short                buttonOval;
  412.             
  413.             GetPenState( &saveState );
  414.  
  415.             // We want to draw the thick line with a normal
  416.             // pen pattern that is 3 pixels wide
  417.             PenNormal();
  418.             PenSize(3,3);
  419.  
  420.             // If the button we are outlining is disabled,
  421.             // draw the outline with a gray pattern.
  422.             if( (*buttonHandle)->contrlHilite == 255 )
  423.             {
  424.                 PenPat(&qd.gray);
  425.             }
  426.  
  427.             // Calculate the curvature to use and draw the thick line
  428.             buttonOval = 2 + (outlineBox.bottom - outlineBox.top) / 2;
  429.             FrameRoundRect(outlineBox,buttonOval,buttonOval);
  430.             
  431.             SetPenState( &saveState );
  432.         }
  433.         SetPort(savePort);
  434.     }
  435. } // DrawDefaultProc
  436.  
  437. //----------------------------------------------------------------------------------------
  438. // MinimalAlertFilter: This is the minimally-functional alert filter that MacApp uses
  439. // in cases where gApplication has not yet been initialized.  TApplication.AlertFilter
  440. // calls this filter as well.
  441. //----------------------------------------------------------------------------------------
  442. #pragma segment MAGlobalsRes
  443.  
  444. pascal Boolean MinimalAlertFilter(DialogPtr theDialog,
  445.                                   EventRecord& theEvent,
  446.                                   short& itemHit)
  447. {
  448.     Boolean            returnValue = false;
  449.     
  450.     switch( theEvent.what )
  451.     {
  452.         case updateEvt:
  453.         {
  454.             if (((DialogPtr)theEvent.message) == theDialog)
  455.             {
  456.                 DrawDefaultProc(theDialog);
  457.             }
  458.             break;
  459.         }    
  460.  
  461.         case keyDown:
  462.         {
  463.             unsigned char theChar = (unsigned char)(((theEvent.message) & charCodeMask));
  464.  
  465.             if ((theChar == chEnter) || (theChar == chReturn))
  466.             {
  467.                 itemHit = ((DialogPeek)theDialog)->aDefItem;
  468.                 DoAlertKeyDown(theDialog, itemHit);
  469.                 returnValue = true;
  470.             }
  471.             else if ( (theChar == '`') || (theChar == chEscape) || ((theChar == '.') && (theEvent.modifiers & cmdKey)))
  472.             {
  473.                 DoAlertKeyDown(theDialog, cancel);
  474.                 itemHit = cancel;
  475.                 returnValue = true;
  476.             }
  477.             
  478.             break;
  479.         }
  480.     }
  481.     
  482.     return returnValue;
  483. } // MinimalAlertFilter 
  484.  
  485. //----------------------------------------------------------------------------------------
  486. // MacAppAlertFilter: 
  487. //----------------------------------------------------------------------------------------
  488. #pragma segment MAGlobalsRes
  489.  
  490. pascal Boolean MacAppAlertFilter(DialogPtr theDialog,
  491.                                  EventRecord& theEvent,
  492.                                  short& itemHit)
  493. {
  494.     if (gApplication)
  495.         return gApplication->AlertFilter(theDialog, theEvent, itemHit);
  496.     else
  497.         return MinimalAlertFilter(theDialog, theEvent, itemHit);
  498. } // MacAppAlertFilter 
  499.  
  500. //----------------------------------------------------------------------------------------
  501. // MacAppAppleEventIdleProc: 
  502. //----------------------------------------------------------------------------------------
  503. #pragma segment MAGlobalsRes
  504.  
  505. pascal Boolean MacAppAppleEventIdleProc(EventRecord& theEventRecord,
  506.                                         long& sleepTime,
  507.                                          RgnHandle& mouseRgn)
  508. {
  509.     if (gApplication)
  510.         return gApplication->AppleEventIdleProc(theEventRecord, sleepTime, mouseRgn);
  511.     else
  512.         return false;
  513. } // MacAppAppleEventIdleProc 
  514.  
  515. //----------------------------------------------------------------------------------------
  516. // MacAppStandardFileFilter: 
  517. //----------------------------------------------------------------------------------------
  518. #pragma segment MAGlobalsRes
  519.  
  520. pascal Boolean MacAppStandardFileFilter(DialogPtr theDialog,
  521.                                         EventRecord* theEvent,
  522.                                         short* itemHit,
  523.                                         void *yourDataPtr)
  524. {
  525.     if (gApplication)
  526.         return gApplication->StandardFileFilter(theDialog, *theEvent, *itemHit, yourDataPtr);
  527.     else
  528.         return false;
  529. } // MacAppStandardFileFilter 
  530.  
  531. //----------------------------------------------------------------------------------------
  532. // ApplicationBeep: 
  533. //----------------------------------------------------------------------------------------
  534. #pragma segment MAGlobalsRes
  535.  
  536. void ApplicationBeep()
  537. {
  538.     if (gApplication)
  539.         gApplication->Beep(2);
  540.     else
  541.         SysBeep(2);
  542. } // ApplicationBeep 
  543.  
  544. //----------------------------------------------------------------------------------------
  545. // CleanupMacApp: 
  546. //----------------------------------------------------------------------------------------
  547. #pragma push
  548. #pragma trace off
  549.  
  550. #pragma segment MAGlobalsRes
  551.  
  552. void CleanupMacApp(void)
  553. {
  554.     SetResLoad(true);                            // Make sure segments can load 
  555.  
  556.     pETSPatch.UnpatchTrap();                    // Guaranteed not to fail 
  557.  
  558.     if (gApplication)
  559.         gApplication->Terminate();
  560.  
  561.     gBusyCursor = (TBusyCursor *)FreeIfObject(gBusyCursor);
  562.     
  563.     if (qNeedsAppleEventMgr || gConfiguration.hasAppleEventMgr)
  564.         AEDisposeDesc(&gServerAddress);
  565.  
  566.     if (gTopHandler)
  567.         gTopHandler->Success();                    // Remove the outermost failure handler
  568.  
  569. #if qDebug
  570.     DebugTerminate();
  571. #endif
  572.  
  573.     UnpatchAll();
  574.  
  575.     gApplication = (TApplication*) FreeIfObject(gApplication);
  576. } // CleanupMacApp 
  577.  
  578. #pragma pop
  579.  
  580. //----------------------------------------------------------------------------------------
  581. // ExitToShellCleanupMacApp: 
  582. //----------------------------------------------------------------------------------------
  583. #pragma push
  584. #pragma trace off
  585.  
  586. #pragma segment MAGlobalsRes
  587.  
  588. pascal void ExitToShellCleanupMacApp(void)
  589. {
  590.     long OldA5 = SetCurrentA5();                // ***** Called from trap patches *****
  591.  
  592.     ExitToShellType oldTrapAddr = (ExitToShellType) pETSPatch.GetOldTrapAddr();
  593.     CleanupMacApp();
  594.     CallExitToShellProc(oldTrapAddr);
  595.     
  596.     SetA5(OldA5);
  597. } // ExitToShellCleanupMacApp 
  598.  
  599. #pragma pop
  600.  
  601. //----------------------------------------------------------------------------------------
  602. // DoneWithTemporaryRegion: Indicates that gTemporaryRegion is no longer in use. Call this
  603. // only if qDebug is true.
  604. //----------------------------------------------------------------------------------------
  605. #if qDebug
  606. #pragma segment MADebug
  607.  
  608. void DoneWithTemporaryRegion()
  609. {
  610.     if (!gBusyTemporaryRegion)
  611.         ProgramBreak("DoneWithTemporaryRegion called, but gTemporaryRegion is not locked");
  612.     gBusyTemporaryRegion = false;
  613.     gUsedBy = "";
  614.     SetEmptyRgn(gTemporaryRegion);
  615. } // DoneWithTemporaryRegion 
  616.  
  617. #endif
  618.  
  619. //----------------------------------------------------------------------------------------
  620. // EnterDebugger: 
  621. //----------------------------------------------------------------------------------------
  622. #if qDebug
  623. #pragma segment MADebug
  624.  
  625. void EnterDebugger(Boolean entering)
  626. {
  627.     if (gBusyCursor)
  628.         gBusyCursor->Activate(!entering);
  629. } // EnterDebugger 
  630.  
  631. #endif
  632.  
  633. //----------------------------------------------------------------------------------------
  634. // ExitMacApp: 
  635. //----------------------------------------------------------------------------------------
  636. #pragma segment MATerminate
  637.  
  638. void ExitMacApp()
  639. {
  640.     ExitToShell();
  641.     // patch will call CleanupMacApp
  642.     
  643. } // ExitMacApp 
  644.  
  645. //----------------------------------------------------------------------------------------
  646. // FreeIfWMgrWindow: 
  647. //----------------------------------------------------------------------------------------
  648. #pragma segment MAGlobalsRes
  649.  
  650. WindowPtr FreeIfWMgrWindow(WindowPtr w, Boolean dispose)
  651. {
  652.     if (w)
  653.     {
  654.          // If the window is visible, hide it first so
  655.         // that the proper activate and deactivate events are sent.
  656.         WindowPeek wPeek = (WindowPeek)w;
  657.         if (wPeek->visible)
  658.             MAHideWindow(w);
  659.         
  660.         if (dispose)
  661.         {
  662.             if (w == qd.thePort)                // Only need to invalidate focus if freed window is the current port
  663.             {
  664.                 if (gApplication)
  665.                     gApplication->InvalidateFocus();
  666.                 SetPort(gWorkPort);
  667.             }
  668.             DisposeWindow(w);
  669.         }
  670.         else
  671.             CloseWindow(w);
  672.     }
  673.     return NULL;                                // convenience to caller 
  674. } // FreeIfWMgrWindow 
  675.  
  676. //----------------------------------------------------------------------------------------
  677. // GetNewCenteredDialog: 
  678. //----------------------------------------------------------------------------------------
  679. #pragma segment MAGlobalsRes
  680.  
  681. DialogPtr GetNewCenteredDialog(ResNumber dialogID,
  682.                                Ptr dStorage,
  683.                                WindowPtr behind)
  684. {
  685.     DialogTHndl dlogTemplate;
  686.  
  687.     SetCursor(&(qd.arrow));
  688.     
  689.     if (gApplication)
  690.         gApplication->InvalidateMouseRegions();
  691.         
  692.     dlogTemplate = (DialogTHndl)GetResource('DLOG', dialogID);
  693.     if (dlogTemplate)
  694.     {
  695.         CenterRectOnScreen(((CRect &) (*dlogTemplate)->boundsRect), true, true, true);
  696.         return GetNewDialog(dialogID, dStorage, behind);
  697.     }
  698.     else
  699.     {
  700.         SysBeep(2);                                // At least give some indication 
  701. #if qDebug
  702.         CStr255 theString;
  703.         ConcatNumber("Unable to find ‘DLOG’ resource ", dialogID, theString);
  704.         ProgramBreak(theString);
  705. #endif
  706.  
  707.     }
  708.     return NULL;
  709. } // GetNewCenteredDialog 
  710.  
  711. //----------------------------------------------------------------------------------------
  712. // GetTextStyleFontInfo: Really a utility, but the gWorkPort isn't reachable from
  713. // UMacAppUtilities
  714. //----------------------------------------------------------------------------------------
  715. #pragma segment MAUtilitiesRes
  716.  
  717. void GetTextStyleFontInfo(const TextStyle& theTextStyle,
  718.                           FontInfo& theFontInfo,
  719.                           short& theFontHeight)
  720. {
  721.     GrafPtr savedPort;
  722.  
  723.     GetPort(&savedPort);
  724.     SetPort(gWorkPort);
  725.     SetPortTextStyle(theTextStyle);
  726.     theFontHeight = MAGetFontInfo(theFontInfo);
  727.     SetPort(savedPort);
  728. } // GetTextStyleFontInfo 
  729.  
  730. //----------------------------------------------------------------------------------------
  731. // DoRealInitToolBox: 
  732. //----------------------------------------------------------------------------------------
  733. #pragma push
  734. // Needs to universal code
  735. #pragma processor 68000
  736. #pragma segment MAMiniInit
  737.  
  738. void DoRealInitToolBox()
  739. {
  740.     // -1 == 0xFFFFFFFF, the largest 32 bit address. Our routine StripLong uses a
  741.     // pre-stripped address gStrippedAddress to avoid the yucky MPW glue. (NOTE: need
  742.     // gStrippedAddress in DefineConfiguration.)
  743.     gStrippedAddress = StripAddress((Ptr) - 1);
  744.  
  745.     // Find out just what kind of environment we're dealing with here 
  746.     DefineConfiguration(gConfiguration);
  747.  
  748.     // Are we background only? If so, bail out...this isn't yet supported by the code.
  749.     if (!gConfiguration.isOnlyBackground)
  750.     {
  751.         // init the toolbox managers
  752.         InitGraf(&qd.thePort);
  753.         InitFonts();
  754.         InitWindows();                            // creates non-relocatable for the WM port 
  755.     
  756.         // _DON'T_ flush disk-inserted or os events or you'll be sorry! 
  757.         FlushEvents(everyEvent - diskMask - osMask, 0);
  758.         SetEventMask(everyEvent);        // allow us to get keyup events too.
  759.     
  760.         InitMenus();
  761.         TEInit();
  762.         InitDialogs(NULL);
  763.     
  764.         CursHandle aCursHandle = GetCursor(watchCursor);    // Watch should be in system
  765.                                                             // file, but just in case…
  766.     
  767.         InitCursor();
  768.         if (aCursHandle)
  769.             SetCursor(*aCursHandle);                        // Change cursor to watch 
  770.     
  771.         // The refnum where the application's resources should be found 
  772.         gApplicationRefNum = CurResFile();
  773.     
  774.         gToolBoxInitialized = true;
  775.     }
  776.     else
  777.     {
  778. #if qDebug
  779.         DebugStr((StringPtr)"\pBackground-only apps not supported");
  780. #endif
  781.         ExitToShell();
  782.     }
  783. } // DoRealInitToolBox 
  784.  
  785. #pragma pop
  786.  
  787. extern pascal void _DataInit();                    // Routine in the A5 globals initializer 
  788.  
  789. //----------------------------------------------------------------------------------------
  790. // FailedInitToolBox: This procedure is intended to be in "Main" which is already loaded
  791. //----------------------------------------------------------------------------------------
  792. #pragma push
  793. // Needs to universal code
  794. #pragma processor 68000
  795. #pragma segment Main
  796.  
  797. void FailedInitToolBox()
  798. {
  799. #if qDebug
  800.     DebugStr((StringPtr)"\pNot enough room to initialize ToolBox managers");
  801. #endif
  802.     ExitToShell();
  803. } // FailedInitToolBox 
  804.  
  805. //----------------------------------------------------------------------------------------
  806. // InitToolBox: 
  807. //----------------------------------------------------------------------------------------
  808. void InitToolBox()
  809. {
  810.     const short kBreathingRoom = 1024;            // Amount of heap space needed for init 
  811.     Size totalSize = 0;
  812.     Size contigSize = 0;
  813.     Handle h = NULL;
  814.  
  815. #if !qPowerPC
  816.     // the heap and stack don't overlap. So there's enough room to init the managers. Make
  817.     // sure that the MAMiniInit Segment can be loaded and that there's still a little Room
  818.     // after that. */
  819.  
  820. #ifndef __MWERKS__
  821.     UnloadSeg(&_DataInit);                        // Toss some ballast
  822. #endif
  823.  
  824.     // "MAMain" this is MacApp's own code that must be resident even before/ during the
  825.     // UMemory startup. GetNamedResource will call RsrvMem which locates the handle as low
  826.     // in memory as possible. We will then lock it there just like "Main". In order for
  827.     // this to work correctly the build system will have to have set the locked bit on the
  828.     // MAMain resource.
  829. #ifndef __MWERKS__
  830.     h = GetNamedResource('CODE', "\pMAMain");
  831. #else
  832.     h = GetNamedResource('CODE', "\pMain");
  833. #endif
  834.     if (h)
  835.         HNoPurge(h);
  836.     else
  837.         FailedInitToolBox();
  838.  
  839.     h = GetNamedResource('CODE', "\pMAMiniInit");
  840.     if (h)
  841.         HNoPurge(h);    // don't let it get squished out of the heap when the grow zone
  842.                         // might get called below. However, since it is not locked it will
  843.                         // float up to the top of the heap when it is entered at
  844.                         // DoRealInitToolBox.
  845.                     
  846.     else
  847.         FailedInitToolBox();
  848. #endif
  849.     
  850.     // Attempt to ensure that there is going to be kBreathingRoom bytes available in the
  851.     // heap so that when the actual toolbox managers are initialized there is a
  852.     // significantly reduced chance that they will express their displeasure with us
  853.     // through SysErr -25 or -2. If the space is not currently available in the zone as
  854.     // shown by PurgeSpace then attempting to allocate it will let growzoneproc operate
  855.     // and grow the zone a little, as necessary. If, after that, we haven't been able to
  856.     // get the breathing room we desire then just give up and fade silently away. (Like
  857.     // the old soldier, not the old executive).
  858.  
  859.     PurgeSpace(&totalSize, &contigSize);
  860.  
  861.     if (totalSize >= kBreathingRoom)
  862.         DoRealInitToolBox();
  863.     else
  864.     {
  865.         h = NewHandle(kBreathingRoom);
  866.         if (h != NULL)                            // get the grow space 
  867.         {
  868.             DisposeHandle(h);
  869.             DoRealInitToolBox();
  870.         }
  871.         else
  872.             FailedInitToolBox();                // Give up 
  873.     }
  874. } // InitToolBox 
  875.  
  876. #pragma pop
  877.  
  878. //----------------------------------------------------------------------------------------
  879. // ValidateConfiguration: 
  880. //----------------------------------------------------------------------------------------
  881. #pragma push
  882. // Needs to universal code
  883. #pragma processor 68000
  884. #pragma segment MAMiniInit
  885.  
  886. Boolean ValidateConfiguration(const Configuration& theConfiguration)
  887.  
  888. {
  889.     Boolean isSupported = true;
  890.  
  891.     // Run the gauntlet of support tests using the conditionally set constants. If any
  892.     // single test fails then the app is considered unsupported on this machine.
  893.  
  894.     // Required minimums 
  895.     isSupported &= theConfiguration.hasROM128K;
  896.     isSupported &= theConfiguration.hasScriptManager;
  897.     isSupported &= theConfiguration.hasHierarchicalMenus;
  898.     isSupported &= theConfiguration.hasStyleTextEdit;
  899.     isSupported &= theConfiguration.hasWaitNextEvent;
  900.     
  901.     // Minimum system version
  902.     isSupported &= theConfiguration.systemVersion >= 0x605;
  903.  
  904.     // Optionally required 
  905.     if (qNeedsColorQD)
  906.         isSupported &= theConfiguration.hasColorQD;
  907.  
  908.     if (qNeedsMC68020)
  909.         isSupported &= ((theConfiguration.processor != gestalt68000) && (theConfiguration.processor != gestalt68010));
  910.  
  911.     if (qNeedsMC68030)
  912.         isSupported &= ((theConfiguration.processor != gestalt68000) && (theConfiguration.processor != gestalt68010) && (theConfiguration.processor != gestalt68020));
  913.  
  914.     if (qNeedsMC68040)
  915.         isSupported &= ((theConfiguration.processor != gestalt68000) && (theConfiguration.processor != gestalt68010) && (theConfiguration.processor != gestalt68020) 
  916.           && (theConfiguration.processor != gestalt68030));
  917.     
  918.     if (qNeedsFPU)
  919.         isSupported &= theConfiguration.hasFPU;
  920.  
  921.  
  922.     // System 7.0 Support 
  923.     if (qNeedsSystem7)
  924.         isSupported &= theConfiguration.systemVersion >= 0x700;
  925.  
  926.     if (qNeedsAppleEventMgr)
  927.         isSupported &= theConfiguration.hasAppleEventMgr;
  928.  
  929.     if (qNeedsEditionMgr)
  930.         isSupported &= theConfiguration.hasEditionMgr;
  931.  
  932.     if (qNeedsHelpMgr)
  933.         isSupported &= theConfiguration.hasHelpMgr;
  934.  
  935.     if (qNeedsAliasMgr)
  936.         isSupported &= theConfiguration.hasAliasMgr;
  937.  
  938.     if (qNeedsFolderMgr)
  939.         isSupported &= theConfiguration.hasFolderMgr;
  940.  
  941.     if (qNeedsProcessMgr)
  942.         isSupported &= theConfiguration.hasProcessMgr;
  943.  
  944.     // skanky hack under A/UX to ensure that all app's are pulled to front early on
  945.     
  946.     if (theConfiguration.hasAUX)
  947.         PullApplicationToFront();
  948.  
  949.     return isSupported;
  950. } // ValidateConfiguration 
  951.  
  952. #pragma pop
  953.  
  954. //----------------------------------------------------------------------------------------
  955. // MAGestaltAttribute: 
  956. //----------------------------------------------------------------------------------------
  957. #pragma push
  958. // Needs to universal code
  959. #pragma processor 68000
  960. #pragma segment Main
  961.  
  962. Boolean MAGestaltAttribute(OSType itsAttr, short itsBit)
  963. {
  964.     long response;
  965.  
  966.     return (Gestalt(itsAttr, &response) == noErr) && (((response >> itsBit) & 1) != 0);
  967.     
  968. } // MAGestaltAttribute 
  969.  
  970.  
  971. //----------------------------------------------------------------------------------------
  972. // DefineConfiguration: 
  973. //----------------------------------------------------------------------------------------
  974. #pragma segment Main
  975.  
  976. void DefineConfiguration(Configuration& theConfiguration)
  977. {
  978.     const short mDesktopBus = 0x0400;
  979.  
  980.     OSErr err;
  981.     long response;
  982.  
  983.     err = Gestalt(gestaltVersion, &response);
  984.     theConfiguration.environsVersion = (short)response;
  985.  
  986.     err = Gestalt(gestaltMachineType, &response);
  987.     theConfiguration.machineType = (short)response;
  988.  
  989.     theConfiguration.hasROM128K = theConfiguration.machineType >= gestaltMac512KE;
  990.     if (theConfiguration.hasROM128K)
  991.         theConfiguration.hasHFS = true;
  992.     else
  993.         theConfiguration.hasHFS = LMGetFSFCBLen() > 0;
  994.  
  995.     err = Gestalt(gestaltSystemVersion, &response);
  996.     theConfiguration.systemVersion = (short)response;
  997.  
  998.     err = Gestalt(gestaltProcessorType, &response);
  999.     theConfiguration.processor = (short)response;
  1000.  
  1001.     err = Gestalt(gestaltFPUType, &response);
  1002.     theConfiguration.hasFPU = response != gestaltNoFPU;
  1003.  
  1004.     err = Gestalt(gestaltQuickdrawVersion, &response);
  1005.     theConfiguration.hasColorQD = response != gestaltOriginalQD;
  1006.  
  1007.     err = Gestalt(gestaltQuickdrawVersion, &response);
  1008.     theConfiguration.has32BitQD = theConfiguration.hasColorQD && (response != gestalt8BitQD);
  1009.  
  1010.     err = Gestalt(gestaltKeyboardType, &response);
  1011.     theConfiguration.keyboardType = (short)response;
  1012.  
  1013.     err = Gestalt(gestaltAppleTalkVersion, &response);
  1014.     theConfiguration.atDrvrVersNum = (short)response;
  1015.  
  1016.     theConfiguration.hasSCSI = MAGestaltAttribute(gestaltHardwareAttr, gestaltHasSCSI);
  1017.  
  1018.     err = Gestalt(gestaltAUXVersion, &response);
  1019.     theConfiguration.hasAUX = response != 0;
  1020.  
  1021.     err = Gestalt(gestaltScriptMgrVersion, &response);
  1022.     theConfiguration.hasScriptManager = theConfiguration.hasROM128K && (response != 0);
  1023.  
  1024.     theConfiguration.hasTempMem = MAGestaltAttribute(gestaltOSAttr, gestaltTempMemSupport);
  1025.  
  1026.     err = Gestalt(gestaltTextEditVersion, &response);
  1027.     theConfiguration.teVersion = response;
  1028.  
  1029.     theConfiguration.hasDesktopBus = (LMGetHWCfgFlags() & mDesktopBus) > 0;
  1030.     
  1031.     theConfiguration.hasHierarchicalMenus = theConfiguration.hasROM128K && TrapExists(_PopUpMenuSelect);
  1032.  
  1033.     theConfiguration.hasStyleTextEdit = theConfiguration.systemVersion >= 0x600;
  1034.     theConfiguration.hasSoundManager = theConfiguration.hasROM128K && TrapExists(_SndDoCommand);
  1035.     theConfiguration.hasWaitNextEvent = theConfiguration.hasROM128K && TrapExists(_WaitNextEvent);
  1036.  
  1037.     // System 7.0 support 
  1038.     theConfiguration.hasAppleEventMgr = MAGestaltAttribute(gestaltAppleEventsAttr, gestaltAppleEventsPresent);
  1039.     theConfiguration.hasEditionMgr = MAGestaltAttribute(gestaltEditionMgrAttr, gestaltEditionMgrPresent);
  1040.     theConfiguration.hasHelpMgr = MAGestaltAttribute(gestaltHelpMgrAttr, gestaltHelpMgrPresent);
  1041.     theConfiguration.hasAliasMgr = MAGestaltAttribute(gestaltAliasMgrAttr, gestaltAliasMgrPresent);
  1042.     theConfiguration.hasFolderMgr = MAGestaltAttribute(gestaltFindFolderAttr, gestaltFindFolderPresent);
  1043.     theConfiguration.hasPopupCDEF = MAGestaltAttribute(gestaltPopupAttr, gestaltPopupPresent);
  1044.     theConfiguration.hasTrueType = MAGestaltAttribute(gestaltFontMgrAttr, gestaltOutlineFonts);
  1045.  
  1046.     // set default values for Process Manager-related items
  1047.     theConfiguration.hasProcessMgr = false;
  1048.     theConfiguration.isOnlyBackground = false;
  1049.     theConfiguration.isHighLevelEventAware = false;
  1050.     
  1051.     // ask process mgr for several values
  1052.     if (MAGestaltAttribute(gestaltOSAttr, gestaltLaunchControl))
  1053.     {
  1054.         theConfiguration.hasProcessMgr = true;
  1055.  
  1056.         ProcessSerialNumber psn;
  1057.         psn.highLongOfPSN = 0;
  1058.         psn.lowLongOfPSN = kCurrentProcess;
  1059.         
  1060.         ProcessInfoRec info;
  1061.         info.processInfoLength = sizeof(ProcessInfoRec);
  1062.         info.processName = NULL;
  1063.         info.processAppSpec = NULL;
  1064.  
  1065.         if (GetProcessInformation(&psn, &info) == noErr)
  1066.         {
  1067.             theConfiguration.isOnlyBackground = (info.processMode & modeOnlyBackground) ? true : false;
  1068.             theConfiguration.isHighLevelEventAware = (info.processMode & modeHighLevelEventAware) ? true : false;
  1069.         }
  1070.     }
  1071.     
  1072.     theConfiguration.hasDragManager = MAGestaltAttribute('drag', 0);
  1073.     theConfiguration.hasThreadManager = MAGestaltAttribute('thds', 0);
  1074.     theConfiguration.hasAOCEToolBox = MAGestaltAttribute('oceu', 0);
  1075.     theConfiguration.hasQDGXGraphics = MAGestaltAttribute('grfx', 0);
  1076.     theConfiguration.hasQDGXPrinting = MAGestaltAttribute('pmgr', 0);
  1077.     theConfiguration.hasASLM = MAGestaltAttribute('aslm', 0);
  1078.     theConfiguration.hasCFM = MAGestaltAttribute(gestaltCFMAttr, gestaltCFMPresent);
  1079.     theConfiguration.hasTranslationManager = MAGestaltAttribute(gestaltTranslationAttr, gestaltTranslationMgrExists);
  1080.     theConfiguration.hasSpeechManager = MAGestaltAttribute(gestaltSpeechAttr, gestaltSpeechMgrPresent);
  1081.     theConfiguration.hasCustomFile = MAGestaltAttribute(gestaltStandardFileAttr, gestaltStandardFile58);
  1082.     theConfiguration.hasQuickTime = (Gestalt(gestaltQuickTime, &response) == noErr);
  1083.     theConfiguration.hasTSM = (Gestalt(gestaltTSMgrVersion, &response) == noErr);
  1084.     
  1085. } // DefineConfiguration 
  1086.  
  1087. #pragma pop
  1088.  
  1089. //----------------------------------------------------------------------------------------
  1090. // ClearTheFPU: Essential one-time initialization
  1091. //
  1092. //    INLINE 0x42A7,                                        // CLR.L -(A7) 
  1093. //           0x42A7,                                        // CLR.L -(A7) 
  1094. //           0xF21F, 0x9800;                                // FMOVEM (A7)+, FPCR/FPSR 
  1095. //----------------------------------------------------------------------------------------
  1096. #if !qPowerPC
  1097. void ClearTheFPU() = { 0x42A7, 0x42A7, 0xF21F, 0x9800 };
  1098. #endif
  1099.  
  1100. //----------------------------------------------------------------------------------------
  1101. // InitUMacApp_Step1 and InitUMacApp_Step3
  1102. //----------------------------------------------------------------------------------------
  1103. #pragma push
  1104. #pragma processor 68000
  1105. // Needs to be universal code
  1106. #pragma segment Main
  1107. // Must be in the Main segment since all other segments get unloaded from here.
  1108.  
  1109. void InitUMacApp_Step1()
  1110. {
  1111.     if (!gToolBoxInitialized)
  1112.         InitToolBox();
  1113.  
  1114.     // Init the basics used by the ErrorMgr (we need this for StdAlert
  1115.     // in case ValidateConfiguration fails)
  1116.     gMacAppAlertFilter = (ProcPtr) & MacAppAlertFilter;
  1117.  
  1118.     if (ValidateConfiguration(gConfiguration))    // Make sure we can run. The programmer
  1119.                                                 // really should have ensured this in
  1120.                                                 // their "M" file but this is a backup
  1121.                                                 // check just in case. After all 68000's
  1122.                                                 // don't really like to RTD.
  1123.     {
  1124. #if !qPowerPC
  1125.         // the main procedure is always compiled with universal code so, the FPU must be
  1126.         // reset before it is used. We could get spurious crashes or worse. Remember:
  1127.         // 2+2=4 every time!
  1128.         if (qNeedsFPU || gConfiguration.hasFPU)
  1129.             ClearTheFPU();
  1130. #endif
  1131.     }
  1132.     else
  1133.     {
  1134.         StdAlert(phUnsupportedConfiguration);
  1135.         ExitToShell();                            // leave the application pronto! 
  1136.     }        
  1137. } // InitUMacApp_Step1 
  1138.  
  1139. //----------------------------------------------------------------------------------------
  1140.  
  1141. void InitUMacApp_Step3(short callsToMoreMasters)
  1142. {
  1143.     // Install MacApp's Memory management system 
  1144.     InitUMemory(callsToMoreMasters);
  1145.  
  1146. #if !qPowerPC
  1147.     UnloadAllSegments();
  1148.     
  1149.     // Force the init segment to be memory resident, so we can call UnloadAllSegs
  1150.     // during init
  1151.     short initSeg = GetSegNumber((ProcPtr) & DoInitUMacApp);
  1152. #ifdef __MWERKS__
  1153. //CW can't set up the jump table if if it has already been set up.  If it's locked 
  1154. //then it's set up.
  1155. {
  1156.     Handle seg;
  1157.     Handle GetSegResource(short segnum);
  1158.     
  1159.     seg = GetSegResource(initSeg);
  1160.     if (IsHandleLocked(seg))                // not yet locked 
  1161.         (*gIsResidentSeg)[initSeg - 1] = true;
  1162.     else
  1163.         SetResidentSegment(initSeg, true);
  1164.     
  1165. }    
  1166. #else
  1167.     SetResidentSegment(initSeg, true);
  1168. #endif
  1169. #endif
  1170.  
  1171.     DoInitUMacApp();                        // do rest of initialization 
  1172.  
  1173. #if !qPowerPC
  1174.     SetResidentSegment(initSeg, false);        // make it non-resident 
  1175.     UnloadAllSegments();
  1176. #endif
  1177. } // InitUMacApp_Step3 
  1178.  
  1179. #pragma pop
  1180.  
  1181. //----------------------------------------------------------------------------------------
  1182. // DoInitUMacApp: Must be in the init segment; unloaded at start of event loop
  1183. //----------------------------------------------------------------------------------------
  1184. #pragma segment MAInit
  1185.  
  1186. void DoInitUMacApp()
  1187. {
  1188.     // Initialize runtime support for objects 
  1189.     InitUObject();
  1190. #if qDebug || qTheDebugger
  1191.     InitUDebug();
  1192. #endif
  1193.  
  1194.     gOrthogonal[vSel] = hSel;
  1195.     gOrthogonal[hSel] = vSel;
  1196.  
  1197.     gErrorParm3 = "";
  1198.  
  1199.     // assign the global text style records from resources
  1200.     MAGetTextStyle(kSystemFontTextStyle, gSystemStyle);
  1201.     MAGetTextStyle(kApplFont12TextStyle, gApplicationStyle);
  1202.     MAGetTextStyle(kApplFont9TextStyle, gApplicationStyle9);
  1203.  
  1204.     //    atexit(&CleanupMacApp);
  1205.     pETSPatch.Install(ExitToShellCleanupMacApp);
  1206.  
  1207.     // Other 1-time initialization 
  1208.     gTemporaryRegion = MakeNewRgn();
  1209.  
  1210.     // Create a work port for our convenience 
  1211.     if (qNeedsColorQD || gConfiguration.hasColorQD)
  1212.         gWorkPort = NewCWindow(NULL, gZeroRect, gEmptyString, false, documentProc, NULL, false, 0);
  1213.     else
  1214.         gWorkPort = NewWindow(NULL, gZeroRect, gEmptyString, false, documentProc, NULL, false, 0);
  1215.  
  1216.     {
  1217.         CRect theGrayRect((*GetGrayRgn())->rgnBBox);
  1218.  
  1219.         gStandardWindowMoveBounds = theGrayRect;
  1220.         gStandardWindowMoveBounds.Inset(CPoint(4, 4));
  1221.  
  1222.         // arbitrary minimum size; maximum size is grayRgn size minus half the title bar
  1223.         gStandardWindowSizeRect = CRect(CPoint(80, 80), theGrayRect.GetSize());
  1224.         gStandardWindowSizeRect.bottom -= 8;
  1225.  
  1226.         gStandardWindowScreenRect = theGrayRect;
  1227.         gStandardWindowScreenRect.Inset(CPoint(16, 16));
  1228.     }
  1229.  
  1230.     InitUBusyCursor();
  1231.     
  1232.     gNullPrintHandler = new TPrintHandler;
  1233.     gNullPrintHandler->IPrintHandler(NULL);
  1234.  
  1235.     gPrintHandler = gNullPrintHandler;
  1236.  
  1237.     // Create the signature lists.
  1238.     gSignatures = new TDynamicArray;
  1239.     gSignatures->IDynamicArray(kEmptyIndex, sizeof(SignatureRec));
  1240.  
  1241.     if (qTemplateViews)
  1242.     {
  1243.         // =============================================== 
  1244.         // Suppress Linker dead stripping of these classes 
  1245.  
  1246.         macroDontDeadStrip(TView);
  1247.         macroDontDeadStrip(TIncludeView);
  1248.         macroDontDeadStrip(TWindow);
  1249.         macroDontDeadStrip(TScrollBar);
  1250.         macroDontDeadStrip(TScrollerScrollBar);
  1251.         macroDontDeadStrip(TScroller);
  1252.  
  1253.         macroDontDeadStrip(TTracker);
  1254.         macroDontDeadStrip(TList);
  1255.         
  1256.         // =============================================== 
  1257.  
  1258.         RegisterStdType("TView", kStdView);
  1259.         RegisterStdType("TView", kStdDefaultView);
  1260.         RegisterStdType("TIncludeView", kStdIncludeAt);
  1261.         RegisterStdType("TWindow", kStdWindow);
  1262.         RegisterStdType("TScrollBar", kStdScrollBar);
  1263.         RegisterStdType("TScrollerScrollBar", kStdScrollerScrollBar);
  1264.         RegisterStdType("TScroller", kStdScroller);
  1265.  
  1266.         RegisterStdType("TTracker", kStdTracker);
  1267.         RegisterStdType("TList", kStdList);
  1268.     }
  1269.     
  1270. #if qDebug
  1271.     // The linker optimizes away the meta information for the following classes by
  1272.     // stripping the ClassInfoProc. MacApp does a SetEltType on lists containing these
  1273.     // classes which requires meta information. Suppress the optimization by doing
  1274.     // suppressing dead stripping. (See UApplication.cp)
  1275.     
  1276.     macroDontDeadStrip(TDocument);
  1277.     macroDontDeadStrip(TEvent);
  1278.     macroDontDeadStrip(TClientCommand);
  1279. #endif
  1280.  
  1281.     InitUAdorners();                            // Temporarily needed for debug window 
  1282.  
  1283.     InitUMenuMgr();
  1284.     InitUClipboardMgr();
  1285.     InitUAppleEvents();
  1286.  
  1287.     // create gServerAddress
  1288.     if (qNeedsAppleEventMgr || gConfiguration.hasAppleEventMgr)
  1289.     {
  1290.         ProcessSerialNumber psn;
  1291.         psn.highLongOfPSN = 0;
  1292.         psn.lowLongOfPSN = kCurrentProcess;
  1293.         FailOSErr(AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(ProcessSerialNumber), &gServerAddress));
  1294.     }
  1295.  
  1296.     // initialize the pseudo-random sequence generation function
  1297.     unsigned long time;
  1298.     GetDateTime(&time);
  1299.     srand((unsigned int)time);
  1300.  
  1301. #if qDebug
  1302.     InitUDialog();
  1303. #endif
  1304.  
  1305. } // DoInitUMacApp 
  1306.  
  1307. //----------------------------------------------------------------------------------------
  1308. // InstallIfPrintHandler: 
  1309. //----------------------------------------------------------------------------------------
  1310. #pragma segment MARes
  1311.  
  1312. void InstallIfPrintHandler(TPrintHandler* aPrintHandler,
  1313.                            TView* aView)
  1314.  
  1315. {
  1316.     TPrintHandler * aNewPrintHandler;
  1317.  
  1318.     if ((aPrintHandler) && (aView) && (aPrintHandler != gNullPrintHandler) && (gPrintHandler != gNullPrintHandler))
  1319.     {
  1320.         aNewPrintHandler = (TPrintHandler *)aPrintHandler->Clone();// signals failure if can't clone
  1321.         aNewPrintHandler->fView = aView;
  1322.         aNewPrintHandler->SetDefaultPrintInfo();
  1323.         if (aView->fDocument)
  1324.             aView->fDocument->AttachPrintHandler(aNewPrintHandler);
  1325.         aView->AttachPrintHandler(aNewPrintHandler);
  1326.     }
  1327. } // InstallIfPrintHandler 
  1328.  
  1329. //----------------------------------------------------------------------------------------
  1330. // MakeNewRgn: 
  1331. //----------------------------------------------------------------------------------------
  1332. #pragma segment MAGlobalsRes
  1333.  
  1334. RgnHandle MakeNewRgn()
  1335. {
  1336.     RgnHandle aRgn = NewRgn();
  1337.     FailNIL(aRgn);
  1338.     return aRgn;
  1339. } // MakeNewRgn 
  1340.  
  1341. //----------------------------------------------------------------------------------------
  1342. // DetermineClassDesc: 
  1343. //----------------------------------------------------------------------------------------
  1344. #pragma segment MAOpen
  1345.  
  1346. const ClassDesc* DetermineClassDesc(IDType signature, const ClassName& className)
  1347. {
  1348.     if (className.IsEmpty())
  1349.         return GetClassDescFromSignature(signature);
  1350.     else
  1351.         return ClassDesc::GetClassDescFromClassName(className);
  1352. } // DetermineClassDesc 
  1353.  
  1354. //----------------------------------------------------------------------------------------
  1355. // GetClassDescFromSignature: 
  1356. //----------------------------------------------------------------------------------------
  1357. #pragma segment MAOpen
  1358.  
  1359. const ClassDesc* GetClassDescFromSignature(IDType signature)
  1360. {
  1361.     CArrayIterator iter(gSignatures);
  1362.     
  1363.     for (ArrayIndex i = iter.FirstIndex(); iter.More(); i = iter.NextIndex())
  1364.     {
  1365.         SignatureRecPtr aSignaturePtr = (SignatureRecPtr)gSignatures->ComputeAddress(i);
  1366.         
  1367.         if (aSignaturePtr->itsSignature == signature)
  1368.             return aSignaturePtr->itsClassDesc;
  1369.     }
  1370.     return NULL;
  1371. } // GetClassDescFromSignature 
  1372.  
  1373. //----------------------------------------------------------------------------------------
  1374. // NewStdObject: 
  1375. //----------------------------------------------------------------------------------------
  1376. #pragma segment MAOpen
  1377.  
  1378. TObject* NewStdObject(IDType signature)
  1379. {
  1380.     const ClassDesc* classDesc = GetClassDescFromSignature(signature);
  1381.  
  1382.     if (classDesc != NULL)
  1383.         return (TObject*)(classDesc->Call_DefaultConstructor());
  1384.     else
  1385.     {
  1386. #if qDebug
  1387.         fprintf(stderr, "signature=‘%4s’\n", (char*) & signature);
  1388.         ProgramBreak("Unable to find class for the given signature");
  1389. #endif
  1390.         Failure(errMissingSignature, 0);
  1391.         
  1392.         return NULL;    // this statement is never executed, but defeats an xlC warning
  1393.     }
  1394. } // NewStdObject 
  1395.  
  1396. //----------------------------------------------------------------------------------------
  1397. // NewObjectBySignature: 
  1398. //----------------------------------------------------------------------------------------
  1399. #pragma segment MAOpen
  1400.  
  1401. TObject* NewObjectBySignature(IDType signature,
  1402.                               const ClassName& className)
  1403. {
  1404.     if (className.IsEmpty())
  1405.         return NewStdObject(signature);
  1406.     else
  1407.         return ClassDesc::NewByClassName(className);
  1408. } // NewObjectBySignature 
  1409.  
  1410. //----------------------------------------------------------------------------------------
  1411. // FindPos: 
  1412. //----------------------------------------------------------------------------------------
  1413. #pragma segment MAGlobalsRes
  1414.  
  1415. short FindPos(const CStr255& pattern, CStr255& source)
  1416. {
  1417.     short i = 0;
  1418.     short j = 0;
  1419.     short position = 0;
  1420.  
  1421.     do
  1422.     {
  1423.         ++i;
  1424.         position = i;
  1425.         for (j = 1; j <= pattern.Length(); ++j)
  1426.             if (!((source[i + j - 1] == pattern[j]) && (CharByte((Ptr) & source, i + j) == 0)))
  1427.             {
  1428.                 position = 0;
  1429.                 break;
  1430.             }
  1431.     } while (!((position > 0) || (i >= source.Length() - pattern.Length() + 1)));
  1432.  
  1433.     return position;
  1434. } // FindPos 
  1435.  
  1436.  
  1437. //----------------------------------------------------------------------------------------
  1438. // ParseTitleTemplate: 
  1439. //----------------------------------------------------------------------------------------
  1440. Boolean ParseTitleTemplate(CStr255& itsTemplate,
  1441.                            short& preDocname,
  1442.                            short& constTitle)
  1443.  
  1444. {
  1445.     const CStr255 kPreDocname = "<<<";
  1446.     const short kPreSize = 3;
  1447.     const CStr255 kPostDocname = ">>>";
  1448.     const short kPostSize = 3;
  1449.  
  1450.     if (itsTemplate.IsEmpty())
  1451.     {
  1452.         preDocname = 1;
  1453.         constTitle = 0;
  1454.     }
  1455.     else
  1456.     {
  1457.         preDocname = FindPos(kPreDocname, itsTemplate);
  1458.         if (preDocname > 0)
  1459.         {
  1460.             itsTemplate.Delete(preDocname, kPreSize);
  1461.             short x = FindPos(kPostDocname, itsTemplate);
  1462.             if (x == 0)
  1463.                 constTitle = preDocname - 1;
  1464.             else
  1465.             {
  1466.                 itsTemplate.Delete(x, kPostSize);
  1467.                 constTitle = itsTemplate.Length() - x + preDocname;
  1468.             }
  1469.         }
  1470.     }
  1471.  
  1472.     return preDocname > 0;
  1473. } // ParseTitleTemplate 
  1474.  
  1475. //----------------------------------------------------------------------------------------
  1476. // RegisterStdType: Register or re-register a type and a class
  1477. //----------------------------------------------------------------------------------------
  1478. #pragma segment MAGlobalsRes
  1479.  
  1480. void RegisterStdType(const CStr255& typeName,
  1481.                      IDType signature)
  1482. {
  1483.     CArrayIterator iter(gSignatures);
  1484.     SignatureRec itsSignatureRec;
  1485.  
  1486.     // If the name can't be found it was probably misspelled or dead-stripped 
  1487.     itsSignatureRec.itsSignature = signature;
  1488.     itsSignatureRec.itsClassDesc = ClassDesc::GetClassDescFromClassName(typeName);
  1489.     if (itsSignatureRec.itsClassDesc == NULL)
  1490.         Failure(minErr, 0);
  1491.  
  1492.     // Replace or add signature as necessary 
  1493.     for (ArrayIndex i = iter.FirstIndex(); iter.More(); i = iter.NextIndex())
  1494.         if (((SignatureRecPtr)(gSignatures->ComputeAddress(i)))->itsSignature == signature)
  1495.             break;
  1496.  
  1497.     if (iter.More())
  1498.         *((SignatureRecPtr)(gSignatures->ComputeAddress(i))) = itsSignatureRec;
  1499.     else
  1500.         gSignatures->InsertElementsBefore(gSignatures->GetSize() + 1, &itsSignatureRec, 1);
  1501. } // RegisterStdType 
  1502.  
  1503. //----------------------------------------------------------------------------------------
  1504. // GetStandardType: 
  1505. //----------------------------------------------------------------------------------------
  1506. #pragma segment MAGlobalsRes
  1507.  
  1508. IDType GetStandardType(const ClassDesc* itsClassDesc)
  1509. {
  1510.     if (itsClassDesc != NULL)
  1511.     {
  1512.         CArrayIterator iter(gSignatures);
  1513.     
  1514.         // find signature
  1515.         for (ArrayIndex i = iter.FirstIndex(); iter.More(); i = iter.NextIndex())
  1516.             if (((SignatureRecPtr)(gSignatures->ComputeAddress(i)))->itsClassDesc == itsClassDesc)
  1517.                 return ((SignatureRecPtr)(gSignatures->ComputeAddress(i)))->itsSignature;
  1518.     }
  1519.  
  1520.     // if we get here, the class descriptor wasn't found in the table of standard signatures
  1521.     return kNoIdentifier;
  1522. } // GetStandardType 
  1523.  
  1524. //----------------------------------------------------------------------------------------
  1525. // SubstituteInTitle: 
  1526. //----------------------------------------------------------------------------------------
  1527. #pragma segment MAGlobalsRes
  1528.  
  1529. Boolean SubstituteInTitle(CStr255& title,
  1530.                           const CStr255& newStuff,
  1531.                           short preDocname,
  1532.                           short constTitle)
  1533. {
  1534.     if (preDocname > 0)
  1535.     {
  1536.         if (constTitle == 0)
  1537.             title = newStuff;
  1538.         else
  1539.         {
  1540.             title.Delete(preDocname, title.Length() - constTitle);
  1541.             title.Insert(newStuff, preDocname);
  1542.         }
  1543.         return true;
  1544.     }
  1545.     else
  1546.         return false;
  1547. } // SubstituteInTitle 
  1548.  
  1549. //----------------------------------------------------------------------------------------
  1550. // UseTemporaryRegion: Call this when you are about to use gTemporaryRegion and qDebug is
  1551. // true. Used with DoneWithTemporaryRegion will prevent you from trying to use
  1552. // gTemporaryRegion from two places at the same time.
  1553. //----------------------------------------------------------------------------------------
  1554. #if qDebug
  1555. #pragma segment MADebug
  1556.  
  1557. void UseTemporaryRegion(const CStr255& byWhom)
  1558. {
  1559.     if (gBusyTemporaryRegion)
  1560.     {
  1561.         fprintf(stderr, "‘%s’ is trying to lock gTemporaryRegion,", (char*)byWhom);
  1562.         fprintf(stderr, "but it is already locked by ‘%s’\n", (char*)gUsedBy);
  1563.         ProgramBreak("Error in UseTemporaryRegion");
  1564.     }
  1565.     else
  1566.     {
  1567.         gBusyTemporaryRegion = true;
  1568.         gUsedBy = byWhom;
  1569.     }
  1570. } // UseTemporaryRegion 
  1571.  
  1572. #endif
  1573.  
  1574.  
  1575. //========================================================================================
  1576. // CLASS CTemporaryRegion
  1577. //========================================================================================
  1578. #undef Inherited
  1579.  
  1580. //----------------------------------------------------------------------------------------
  1581. // CTemporaryRegion::new: 
  1582. //----------------------------------------------------------------------------------------
  1583. #pragma segment MAGlobalsRes
  1584.  
  1585. void* CTemporaryRegion::operator new(size_t size)
  1586. {
  1587.     return ::operator new(size);
  1588. }
  1589.  
  1590. //----------------------------------------------------------------------------------------
  1591. // CTemporaryRegion::delete: 
  1592. //----------------------------------------------------------------------------------------
  1593. #pragma segment IteratorRes
  1594.  
  1595. void CTemporaryRegion::operator delete(void*)
  1596. {
  1597. }
  1598.  
  1599. //----------------------------------------------------------------------------------------
  1600. // CTemporaryRegion::CTemporaryRegion: 
  1601. //----------------------------------------------------------------------------------------
  1602. #pragma segment MAGlobalsRes
  1603.  
  1604. CTemporaryRegion::CTemporaryRegion()
  1605. {
  1606.     // Simple single level cache for first cut
  1607.     // take the cached region if available otherwise make one up to give out
  1608.     if (fCachedRgn)
  1609.     {
  1610.         fRgnHandle = fCachedRgn;
  1611.         fCachedRgn = NULL;
  1612.     }
  1613.     else
  1614.     {
  1615.         fRgnHandle = MakeNewRgn();
  1616.     }
  1617.  
  1618.     // Setup the FailInfo to catch any failures while this object is in scope
  1619.     fFailInfo.Reset();        // ensure that fFailInfo is in an initial state
  1620.     fFailInfo.SetCleanupProc(CTemporaryRegion::CallCleanup, this);
  1621. } // CTemporaryRegion::CTemporaryRegion 
  1622.  
  1623. //----------------------------------------------------------------------------------------
  1624. // CTemporaryRegion::~CTemporaryRegion: 
  1625. //----------------------------------------------------------------------------------------
  1626. #pragma segment MAGlobalsRes
  1627.  
  1628. CTemporaryRegion::~CTemporaryRegion()
  1629. {
  1630.     this->Cleanup();
  1631.  
  1632.     Success(fFailInfo);
  1633. } // CTemporaryRegion::~CTemporaryRegion 
  1634.  
  1635. //----------------------------------------------------------------------------------------
  1636. // CTemporaryRegion::Cleanup: 
  1637. //----------------------------------------------------------------------------------------
  1638. #pragma segment MAGlobalsRes
  1639.  
  1640. void CTemporaryRegion::Cleanup()
  1641. {
  1642.     // return to the cache if not already full
  1643.     if (fCachedRgn)
  1644.     {
  1645.         fRgnHandle = DisposeIfRgnHandle(fRgnHandle);
  1646.     }
  1647.     else
  1648.     {
  1649.         fCachedRgn = fRgnHandle;
  1650.         fRgnHandle = NULL;
  1651.     }
  1652. } // CTemporaryRegion::Cleanup 
  1653.  
  1654. //----------------------------------------------------------------------------------------
  1655. // CTemporaryRegion::CallCleanup: 
  1656. //----------------------------------------------------------------------------------------
  1657. #pragma segment MAGlobalsRes
  1658.  
  1659. /*static*/ void CTemporaryRegion::CallCleanup(void* context)
  1660. {
  1661.     ((CTemporaryRegion*) context)->Cleanup();
  1662. } // CTemporaryRegion::CallCleanup 
  1663.  
  1664. //========================================================================================
  1665. // GLOBAL Procedures
  1666. //========================================================================================
  1667. #undef Inherited
  1668.  
  1669. //----------------------------------------------------------------------------------------
  1670. // FindProcessBySignature: 
  1671. //----------------------------------------------------------------------------------------
  1672. #pragma segment MAGlobalsRes
  1673.  
  1674. OSErr FindProcessBySignature(OSType sig,
  1675.                              ProcessSerialNumber& psn,
  1676.                              FSSpec* fileSpec)
  1677. {
  1678.     OSErr err;
  1679.     
  1680.     ProcessInfoRec info;
  1681.  
  1682.     psn.highLongOfPSN = 0;
  1683.     psn.lowLongOfPSN  = kNoProcess;
  1684.     do
  1685.     {
  1686.         err= GetNextProcess(&psn);
  1687.         if( err == noErr )
  1688.         {
  1689.  
  1690.             info.processInfoLength = sizeof(ProcessInfoRec);
  1691.             info.processName = NULL;
  1692.             info.processAppSpec = fileSpec;
  1693.  
  1694.             err= GetProcessInformation(&psn, &info);
  1695.         }
  1696.     } while( (err == noErr) && info.processSignature != sig );
  1697.  
  1698.     if( err == noErr )
  1699.         psn = info.processNumber;
  1700.  
  1701.     return err;
  1702. } // FindProcessBySignature 
  1703.  
  1704.  
  1705. //----------------------------------------------------------------------------------------
  1706. // GetSysVolume: 
  1707. //----------------------------------------------------------------------------------------
  1708. #pragma segment MAGlobalsRes
  1709.  
  1710. OSErr GetSysVolume(short& vRefNum)
  1711. {
  1712.     OSErr theErr;
  1713.     
  1714.     if (qNeedsFolderMgr || gConfiguration.hasFolderMgr)
  1715.     {
  1716.         long dir;
  1717.         
  1718.         theErr = FindFolder(kOnSystemDisk, kSystemFolderType, false, &vRefNum, &dir);
  1719.     }
  1720.     else
  1721.     {
  1722.         SysEnvRec environment;
  1723.         
  1724.         theErr = SysEnvirons(1, &environment);
  1725.         vRefNum = environment.sysVRefNum;
  1726.     }
  1727.     return theErr;
  1728. } // GetSysVolume 
  1729.  
  1730.  
  1731. //----------------------------------------------------------------------------------------
  1732. // GetIndVolume: 
  1733. //----------------------------------------------------------------------------------------
  1734. #pragma segment MAGlobalsRes
  1735.  
  1736. OSErr GetIndVolume(short index,
  1737.                    short& vRefNum)
  1738. {
  1739.     ParamBlockRec pb;
  1740.     OSErr err;
  1741.  
  1742.     pb.volumeParam.ioCompletion = NULL;
  1743.     pb.volumeParam.ioNamePtr = NULL;
  1744.     pb.volumeParam.ioVolIndex = index;
  1745.  
  1746.     err = PBGetVInfo(&pb, false);
  1747.  
  1748.     vRefNum = pb.volumeParam.ioVRefNum;
  1749.     return err;
  1750. } // GetIndVolume 
  1751.  
  1752.  
  1753. //----------------------------------------------------------------------------------------
  1754. // VolHasDesktopDB: 
  1755. //----------------------------------------------------------------------------------------
  1756. #pragma segment MAGlobalsRes
  1757.  
  1758. OSErr VolHasDesktopDB(short vRefNum, Boolean& hasDesktop)
  1759. {
  1760.     HParamBlockRec pb;
  1761.     GetVolParmsInfoBuffer info;
  1762.  
  1763.     pb.ioParam.ioCompletion = NULL;
  1764.     pb.ioParam.ioVRefNum = vRefNum;
  1765.     pb.ioParam.ioNamePtr = NULL;
  1766.     pb.ioParam.ioBuffer = (Ptr) & info;
  1767.     pb.ioParam.ioReqCount = sizeof(GetVolParmsInfoBuffer);
  1768.  
  1769.     OSErr err = ::PBHGetVolParmsSync(&pb);
  1770.  
  1771.     hasDesktop = (err == noErr) && ((info.vMAttrib & (1L << bHasDesktopMgr)) != 0);
  1772.  
  1773.     return err;
  1774.     
  1775. } // VolHasDesktopDB 
  1776.  
  1777.  
  1778. //----------------------------------------------------------------------------------------
  1779. // FindAppOnVolume: 
  1780. //----------------------------------------------------------------------------------------
  1781. #pragma segment MAGlobalsRes
  1782.  
  1783. OSErr FindAppOnVolume(OSType sig,
  1784.                       short vRefNum,
  1785.                       FSSpec& thefile)
  1786. {
  1787.     DTPBRec pb;
  1788.     OSErr err;
  1789.  
  1790.     pb.ioCompletion = NULL;
  1791.     pb.ioVRefNum = vRefNum;
  1792.     pb.ioNamePtr = NULL;
  1793.     if ((err = PBDTGetPath(&pb)) != noErr)
  1794.         return err;                                    // Puts DT refnum into pb.ioDTRefNum
  1795.     short refNum = pb.ioDTRefNum;
  1796.  
  1797.     pb.ioCompletion = NULL;
  1798.     pb.ioDTRefNum = refNum;
  1799.     pb.ioIndex = 0;
  1800.     pb.ioFileCreator = sig;
  1801.     pb.ioNamePtr = (StringPtr) thefile.name;
  1802.     err = PBDTGetAPPLSync(&pb);                        // Find it!
  1803.  
  1804.     if( err == fnfErr )
  1805.         err = afpItemNotFound;                        // Bug in PBDTGetAPPL
  1806.     if( err )
  1807.         return err;                                    // Returns afpItemNotFound if app wasn't found.
  1808.  
  1809.     thefile.vRefNum = vRefNum;
  1810.     thefile.parID = pb.ioAPPLParID;
  1811.     return err;
  1812. } // FindAppOnVolume 
  1813.  
  1814.  
  1815. //----------------------------------------------------------------------------------------
  1816. // LaunchAppByFSSpec: 
  1817. //----------------------------------------------------------------------------------------
  1818. #pragma segment MAGlobalsRes
  1819.  
  1820. OSErr LaunchAppByFSSpec(const FSSpec& fileSpec,
  1821.                            LaunchFlags launchControlFlags,
  1822.                            ProcessSerialNumber& psn)
  1823. {
  1824.     LaunchParamBlockRec pb;
  1825.     OSErr err;
  1826.     FSSpec localFSSpec = fileSpec;        // so we can take its address below
  1827.  
  1828.     pb.launchBlockID = extendedBlock;
  1829.     pb.launchEPBLength = extendedBlockLen;
  1830.     pb.launchFileFlags = launchNoFileFlags;
  1831.     pb.launchControlFlags = launchControlFlags | launchNoFileFlags;
  1832.     pb.launchAppSpec = &localFSSpec;
  1833.     pb.launchAppParameters = NULL;
  1834.  
  1835.     err = LaunchApplication(&pb);
  1836.     if (err == noErr)
  1837.         psn = pb.launchProcessSN;
  1838.     return err;
  1839. } // LaunchAppByFSSpec 
  1840.  
  1841.  
  1842. //----------------------------------------------------------------------------------------
  1843. // LaunchBySignature: 
  1844. //----------------------------------------------------------------------------------------
  1845. #pragma segment MAGlobalsRes
  1846.  
  1847. OSErr LaunchBySignature(OSType sig,
  1848.                         ProcessSerialNumber& psn,
  1849.                         FSSpec* fileSpec,
  1850.                         Boolean* launched,
  1851.                         Boolean allowLaunch,
  1852.                         LaunchFlags launchControlFlags)
  1853. {
  1854.     OSErr err;
  1855.     short sysVRefNum;
  1856.  
  1857.     // First see if it's already running:
  1858.  
  1859.     if (launched)
  1860.         *launched = false;
  1861.     err = FindProcessBySignature(sig, psn, fileSpec);
  1862.  
  1863.     if (err == noErr)
  1864.         if ((launchControlFlags & launchDontSwitch) == 0)
  1865.             return SetFrontProcess(&psn);        // They wanted to switch to it…
  1866.  
  1867.     if (err != procNotFound || !allowLaunch)
  1868.         return err;
  1869.  
  1870.     // Well, it's not running but it's okay to launch it. Let's have a look around:
  1871.  
  1872.     if ((err = GetSysVolume(sysVRefNum)) != noErr)
  1873.         return err;                                    // Find boot volume
  1874.     short vRefNum = sysVRefNum;                        // Start search with boot volume
  1875.     short index = 0;
  1876.     do
  1877.     {
  1878.         if (index == 0 || vRefNum != sysVRefNum)
  1879.         {
  1880.             Boolean hasDesktopDB;
  1881.  
  1882.             if ((err = VolHasDesktopDB(vRefNum, hasDesktopDB)) != noErr)
  1883.                 return err;
  1884.             if (hasDesktopDB)
  1885.             {
  1886.                 FSSpec file;
  1887.  
  1888.                 // If volume has a desktop DB,
  1889.                 err = FindAppOnVolume(sig, vRefNum, file);    // ask it to find app
  1890.                 if (err == noErr)
  1891.                 {
  1892.                     // If found,
  1893.                     if (fileSpec)
  1894.                         *fileSpec = file;
  1895.                     if (launched)
  1896.                         *launched = true;
  1897.                     return LaunchAppByFSSpec(file, launchControlFlags, psn);    // Launch it!
  1898.                 }
  1899.                 else if (err != afpItemNotFound)
  1900.                     return err;
  1901.             }
  1902.         }
  1903.         err = GetIndVolume(++index, vRefNum);    // Else go to next volume
  1904.     } while (err == noErr);                        // Keep going until we run out of vols
  1905.  
  1906.     if( err==nsvErr || err==afpItemNotFound )
  1907.         err= fnfErr;                                    // File not found on any volume
  1908.     return err;
  1909. } // LaunchBySignature 
  1910.