home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / POV-Ray 3.0.2 / src / MacSource / Pov.c < prev    next >
Encoding:
Text File  |  1997-06-25  |  93.1 KB  |  3,626 lines  |  [TEXT/CWIE]

  1. /*==============================================================================
  2. Project:    POV-Ray
  3.  
  4. Version:    3
  5.  
  6. File:    Pov.c
  7.  
  8. Description:
  9.     This file contains the main program and most other Macintosh-specific
  10.     routines for the Persistence Of Vision raytracer (POV-Ray.)
  11. ------------------------------------------------------------------------------
  12. Mac Authors:
  13.     Thomas Okken, David Lichtman, Glenn Sugden
  14.     Jim Nitchals, David Harr, Eduard [esp] Schwan
  15. ------------------------------------------------------------------------------
  16.     from Persistence of Vision(tm) Ray Tracer
  17.     Copyright 1996 Persistence of Vision Team
  18. ------------------------------------------------------------------------------
  19.     NOTICE: This source code file is provided so that users may experiment
  20.     with enhancements to POV-Ray and to port the software to platforms other 
  21.     than those supported by the POV-Ray Team.  There are strict rules under
  22.     which you are permitted to use this file.  The rules are in the file
  23.     named POVLEGAL.DOC which should be distributed with this file. If 
  24.     POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  25.     Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  26.     Forum.  The latest version of POV-Ray may be found there as well.
  27.  
  28.     This program is based on the popular DKB raytracer version 2.12.
  29.     DKBTrace was originally written by David K. Buck.
  30.     DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  31. ------------------------------------------------------------------------------
  32. More Info:
  33.     This Macintosh version of POV-Ray was updated and compiled by Eduard Schwan
  34.     and now builds under Apple MPW 3.3.x, Metrowerks CodeWarrior CW6+, and
  35.     Symantec C 7, for the 68K and Power Macintosh.
  36.     The Macintosh code was based (loosely) on the original DKB 0.5 port by
  37.     Thomas Okken and David Lichtman, with some help from Glenn Sugden.
  38.     Jim Nitchals was instrumental in getting 1.0 out, Jim and Eduard jointly
  39.     pulled off 2.x with help from Dave Harr for initial Balloon help and the
  40.     custom palette code, and 3.0 was done by Eduard Schwan.
  41.  
  42.     For bug reports regarding the Macintosh version, you may contact:
  43.     Eduard [esp] Schwan -- esp Software
  44.         CompuServe: 71513,2161
  45.         Internet: 71513.2161@compuserve.com
  46. ------------------------------------------------------------------------------
  47. Change History:
  48.     920815    [jln]    version 1.0 Mac released.
  49.     920908    [esp]    version 1.1 alpha Mac
  50.     921228    [esp]    version 1.1 beta Mac
  51.     930113    [esp]    1.1b20 release, looks pretty stable to me
  52.     930725    [esp]    version 1.75b3 released (cancel parse bug fixed)
  53.     930903    [esp]    version 1.91b2 released (VIB bug fixed)
  54.     930911    [esp]    version 1.91b4 released (include path uses SFGetFile now)
  55.     930918    [esp]    version 1.92b1 released (AppFriendly works better, ImageWindPos restored OK)
  56.     930929    [esp]    version 1.94b2 released (removed QuickTime "No Image Comp" warning)
  57.     931001    [esp]    version 2.0 finished (Released on 10/4/93)
  58.     931005    [esp]    version 2.01b fixed cmd-O bug (every other file open fails)
  59.     931005    [esp]    version 2.01b undo & redo scroll window to where the action is
  60.     931018    [esp]    version 2.01b Changed RenderOpts AutoBound from checkbox to popup,
  61.                     display credits at startup, not 1st render, fixed include prefs logic
  62.     931119    [djh]    2.0.1 source conditionally compiles for PPC machines, keyword __powerc
  63.     940204    [esp]    2.2 prepare for release - bound slabs default OFF
  64.     940416    [PFS]    2.2.1 greatly reworked to clean up PPC support and provide CodeWarrior projects
  65.     940430    [esp]    Preliminary 3.0a1 work
  66.     940520    [esp]    2.2+ updated for Metrowerks DR/3 release
  67.     950105    [esp]    3.0a13 updated for Metrowerks CW5 and Symantec 7.0.3
  68.     950629    [esp]    3.0a18 continue splitting this monolithic file into other smaller files
  69.     960210    [esp]    3.0b5 Added beta timeout code, in preparation for public beta
  70.     960421    [esp]    3.0b6 Loosened coupling to editor, so I could add the TE32K code.
  71.     960714    [esp]    3.0F1 POV-Ray 3.0 final let loose on the world, finally!
  72.     970502    [tf]    3.0.2 Thorsten Froehlich(106325,3677) contributed undo/redo code
  73. ==============================================================================*/
  74.  
  75. #if !defined(POVMACHEADERS_PCH)
  76.  
  77. /*==== POV-Ray std headers ====*/
  78. #include "config.h"
  79.  
  80. #include "PovMac.h"
  81. #include "povray.h"    // for alt_main
  82.  
  83.  
  84. /*==== Standard C headers ====*/
  85. #include <stdlib.h>
  86. #include <setjmp.h>
  87.  
  88.  
  89. /*==== Macintosh-specific headers ====*/
  90.  
  91. #include <Types.h>
  92. #include <Controls.h>
  93. #include <Dialogs.h>
  94. #include <Files.h>
  95. #include <Memory.h>
  96. #include <Menus.h>
  97. #include <Events.h>
  98. #include <OSUtils.h>
  99. #include <Packages.h>
  100. #include <PictUtils.h>
  101. #include <QuickDraw.h>
  102. #include <Resources.h>
  103. #include <Windows.h>
  104. #include <AppleEvents.h>
  105. #include <scrap.h>
  106. #include <sound.h>
  107. #include <DiskInit.h>
  108. #include <Gestalt.h>
  109. #include <Folders.h>
  110. #include <Balloons.h>        /* kHMHelpMenuID */
  111. #include <errors.h>            /* dupFNErr, etc */
  112. #include <fonts.h>
  113. #include <segload.h>        /* UnloadSeg */
  114. #include <eppc.h>            /* kHighLevelEvent */
  115. #include <traps.h>            /* _Unimplemented */
  116. #include <string.h>            /* strcpy/cat */
  117. #include <toolutils.h>        /* BitTst, etc */
  118.  
  119. #if defined(powerc) || defined (__powerc)
  120. #include <CodeFragments.h>        /* kUnresolvedAddress */
  121. #endif
  122.  
  123. #if defined (applec) || defined(__MWERKS__)
  124. #include <strings.h>        /* p2cstr */
  125. #endif // apple
  126.  
  127. // Debug with profiler
  128. #if defined(THINK_C) && defined(NEEDS_PROF)
  129. #include <profile.h>
  130. #endif
  131.  
  132.  
  133. /*==== POV-Ray text editor header ====*/
  134. #include "TextEditor.h"
  135. #include "UndoRedoSystem.h"
  136.  
  137.  
  138. /*==== POV Mac Library routines =====*/
  139. #include "UtilLib.h"
  140.  
  141. #include "ArgvTrix.h"
  142. #include "VolsPaths.h"
  143. #include "FileQueue.h"
  144. #include "AEUtils.h"
  145.  
  146. #include "Animate.h"
  147. #include "SaveCmpPict.h"
  148. #include "FileQueue.h"
  149. #include "ImageWindow.h"
  150. #include "ProgressDialog.h"
  151. #include "TemplateMenu.h"
  152. #include "AboutBox.h"
  153. #include "SplashScreen.h"
  154. #include "OptOut.h"       // DISTRIBUTION_MESSAGE
  155.  
  156. #include "AppPrefs.h"
  157. #include "FilePrefs.h"
  158.  
  159. #endif // POVMACHEADERS_PCH
  160.  
  161. /*==== General definitions ====*/
  162.  
  163. // preview picture rsrc id
  164. #define    kDemoPICTrsrcID            1001
  165.  
  166. #if defined(applec)
  167. /* entry point to %a5init segment, for disposal after init */
  168. extern void _DataInit();
  169. #endif // applec
  170.  
  171. #if defined(__MWERKS__)
  172. #include "unix.mac.h"    // for _fcreator, _ftype (setting file type)
  173. #endif
  174.  
  175.  
  176. /*==== Global variables (external scope) ====*/
  177.  
  178. #if defined(__MRC__)
  179. QDGlobals qd;
  180. #endif
  181.  
  182. p2w_WindowPtr_t        gp2wWindow = NULL;            // the Status (text) window
  183.  
  184. Boolean                gHasAppleEvents = false;    // Apple Events available for doing shutdown?
  185. Boolean                gHas32BitQD = false;         // is 32 bit Quickdraw available for depth & dithering
  186. Boolean                gHasPictUtils = false;        // is Picture Utils (extract best palette) avail?
  187. Boolean                gHasImageCompressionMgr = false; // Is image compression available?
  188. Boolean                gHasQuickTime = false;         // Is QuickTime available?
  189. long                gQTVersion;                    // QuicktTime version from Gestalt
  190.  
  191. Boolean                gInBackground = false;        // is the program currently switched out
  192. Boolean                gDoingRender;                // for determining the menu states
  193. Rect                gDragBounds;                // window dragging boundary
  194.  
  195. StringPtr            gDistMessage;                // concatenated from OPTIONS.H strings
  196.  
  197. Boolean                gDoingBatchODOCs = false;     // in the middle of ODOC, postpone other odocs
  198.  
  199. Boolean                gCanUndo = false;            // can we undo this operation?
  200. Boolean                gCanRedo = false;            // can we redo this operation?
  201.  
  202. short                gAppRefNum = -1;            // The application's resource file refnum
  203.  
  204. Str31                gPictFname;                    // name of pict output file
  205. Str31                gOutFname;                    // name of other output file
  206.  
  207. ComponentInstance    gtheSCComponent = NULL;    
  208.  
  209. /*==== Global variables (local scope) ====*/
  210.  
  211. static Boolean        gAutoShutdown = false;        // flag for auto-shutdown on completion
  212. static Boolean        gBeginRendering = false;    // True when user picks Render from menu
  213. static SndChannelPtr    gSndChannelPtr = NULL;    // Beep this!
  214.  
  215. // Animation-related
  216. static Boolean        gInAnimationLoop = false;    // True when rendering an animation file
  217. static AnimRec_t    gAnimRec;                    // current animation frame/clock info
  218.  
  219.  
  220. static jmp_buf        gSetJmpEnv;                    // exit state
  221.  
  222. // resource file reference numbers
  223. static short        SrcResRefNum = kRsrcFileClosed;
  224.  
  225. static long            gPrevTickCount;                // Time of last WNE time slice
  226. static long            gWNEReleaseTicks;            // how long to yield to other apps
  227. static RgnHandle    gCursorRgn;
  228.  
  229. static MenuHandle    myMenus[num_of_menus];
  230. static MenuHandle    mySubMenus[num_of_submenus];
  231. static EventRecord    gTheEvent;
  232.  
  233. static Boolean        gQuit = false;
  234. static short        gPaused = 0;
  235.  
  236. static short        gRenderedOK = false;
  237. static long            TargetTicks;
  238.  
  239. // out-of-mem reserve space, for MEMALLOC.C
  240. #define RESERVE_MEM_SIZE    100000L
  241.  
  242. // stack tracking
  243. static    long    gStackBase;
  244. static    long    gStackMax;
  245.  
  246.  
  247.  
  248. /*==== BETA timeout stuff ====*/
  249. // uncomment this line to turn on the beta-timeout code
  250. // #define DO_BETA
  251.  
  252. #ifdef DO_BETA
  253. #include <Time.h>
  254. #define    rDlg_BetaTimeout    6969            // Freudian dialog ID
  255. #define    BETA_YEAR            97                // This is the y/m/d it will time out after
  256. #define    BETA_MONTH            6
  257. #define    BETA_DAY            30
  258. static float            gTimeoutFlag = 0.0; // this will be set to >0 if NOT OK to run
  259. static struct tm        *gThetmPtr;
  260. #endif // DO_BETA
  261.  
  262.  
  263.  
  264. // ---------------------------------------------------------------------
  265. // return the state of the Quit flag
  266. #pragma segment Main
  267.  
  268. Boolean AppIsQuitting(void)
  269.     {
  270.     return gQuit;
  271.     } // AppIsQuitting()
  272.  
  273.  
  274. // ---------------------------------------------------------------------
  275. // turn ON the Quit flag
  276. #pragma segment Main
  277.  
  278. void SetAppQuit(void)
  279.     {
  280.     gQuit = true;
  281.     } // SetAppQuit()
  282.  
  283.  
  284. // ---------------------------------------------------------------------
  285. // Set default (current) dir to that of the POV-Ray app, so any C-library
  286. // file open calls will look for files in this directory.
  287. OSErr SetCurrentDirToAppDir(void)
  288. {
  289.     OSErr    anError;
  290.     FSSpec    myAppSpec;
  291.     ProcessSerialNumber    myPSN;
  292.     ProcessInfoRec        myProcessRec;
  293.  
  294.     // Find info about our process
  295.     myPSN.highLongOfPSN = 0;
  296.     myPSN.lowLongOfPSN  = kCurrentProcess; // ourself
  297.     myProcessRec.processAppSpec = &myAppSpec;
  298.     myProcessRec.processInfoLength = sizeof(myProcessRec);
  299.     myProcessRec.processName = NULL;
  300.     anError = GetProcessInformation(&myPSN, &myProcessRec);
  301.     // set current directory to the application directory
  302.     if (!anError)
  303.         anError = HSetVol(NULL, myAppSpec.vRefNum, myAppSpec.parID);
  304.     return anError;
  305. } // SetCurrentDirToAppDir
  306.  
  307.  
  308. // ---------------------------------------------------------------------
  309. // Dispose and recreate an empty file list queue
  310. static void HaltFileQ()
  311. {
  312.     // halt any multi-doc processes
  313.     gDoingBatchODOCs = false;
  314.  
  315.     FileQ_d();    // Tear down ODOC File Queue
  316.     FileQ_c();  // re-create it, empty
  317. } // HaltFileQ
  318.  
  319.  
  320. // ---------------------------------------------------------------------
  321. // Calculate MultiFinder yield time as a function of hogginess.
  322. // If the user is making POV-Ray extra friendly, yield more background
  323. // ticks.  If user's making us extra hoggy, return right away.
  324. //APGet_TimeSlice() gWNEReleaseTicks
  325. //     1                4
  326. //     2                3
  327. //     3                2
  328. //     4                1
  329. //     5                0
  330. static void CalcCpuReleaseTicks(Boolean AllowVerbose)
  331. {
  332.     // gWNEReleaseTicks = # of ticks to allow for other apps before returning
  333.     gWNEReleaseTicks = (eThrottle_Highest - APGet_TimeSlice());
  334.     if ( AllowVerbose )
  335.         if ( (**gPrefs2Use_h).progress >= eProgDebug )
  336.             printf("-d AppPriority=%ld, ReleaseTimes=%ld\n", APGet_TimeSlice(), gWNEReleaseTicks);
  337. }
  338.  
  339.  
  340. // ---------------------------------------------------------------------
  341. // Convert current date/time into an ASCII C string for display
  342. static char * GetDateTimeString(char *pbuff)
  343. {
  344.     unsigned long    dtsecs;
  345.     char            tbuff[64];
  346.     
  347.     // Does anybody really know what time it is?
  348.     GetDateTime(&dtsecs);
  349.  
  350.     // convert date to string
  351.     IUDateString(dtsecs, shortDate, (StringPtr)tbuff);
  352.     p2cstr((StringPtr)tbuff);
  353.     strcpy(pbuff, tbuff);
  354.  
  355.     // put date/time separator in buffer
  356.     strcat(pbuff, "  ");
  357.  
  358.     // convert time to string
  359.     IUTimeString(dtsecs, true, (StringPtr)tbuff);
  360.     p2cstr((StringPtr)tbuff);
  361.     strcat(pbuff, tbuff);
  362.  
  363.     // "give user his filled buffer back"
  364.     return (pbuff);
  365. } // GetDateTimeString
  366.  
  367.  
  368. // ------------------------------------------------------------------
  369. // Display some general debugging information, if user has dubugging flag turned on
  370. #pragma segment Inits
  371.  
  372. static void DisplayConfigInfo(void)
  373.     {
  374.     long        gestaltResponse;
  375.     OSErr        anError = noErr;
  376.  
  377.     printf("! --- General System Information ---\n");
  378.     printf("! Available Memory:     %d KBytes\n", FreeMem()/1024);
  379.  
  380.     if (Gestalt(gestaltSystemVersion, &gestaltResponse) == noErr)
  381.         printf("! MacOS system version:    %04lx\n", gestaltResponse);
  382.  
  383.     printf("! AppleScriptExists:    %d\n", gAppleScriptAvail);
  384.  
  385.     // QuickTime and ImageCompression mgr
  386.     printf("! QuickTimeVersion:     0x%08lx   ImageCompressionExists:  %d\n", gQTVersion, gHasImageCompressionMgr);
  387.  
  388.     if (Gestalt(gestaltSysArchitecture, &gestaltResponse) == noErr)
  389.         {
  390.         printf("! CPU type: ");
  391.         if (gestaltResponse == gestaltPowerPC)
  392.             printf("PowerPC\n");
  393.         else
  394.             {
  395.             // what kind of 68k CPU?
  396.             Gestalt(gestaltProcessorType, &gestaltResponse);
  397.             printf("680%2d",(gestaltResponse-gestalt68000)*10); // 00,10,20...
  398.             // what kind of FPU?
  399.             printf("    FPU type: ");
  400.             Gestalt(gestaltFPUType, &gestaltResponse);
  401.             if (gestaltResponse == gestaltNoFPU)
  402.                 printf("None\n",(gestaltResponse-gestalt68000)*10);
  403.             else if (gestaltResponse == gestalt68040FPU)
  404.                 printf("Built-in\n",(gestaltResponse-gestalt68000)*10);
  405.             else
  406.                 printf("6888%1d\n",gestaltResponse);
  407.             }
  408.         }
  409.  
  410.     // Check for Software FPU installed if compiled for 68K (no problem if on PPC)
  411. #if !defined(powerc) && !defined (__powerc)
  412.     {
  413.     if (Gestalt('FPUE', &gestaltResponse) == noErr)
  414.         {
  415.         printf("! NOTE: 68K SoftwareFPU extension detected...\n");
  416.         printf("!       (Floating point operations are emulated in software.)\n");
  417.         printf("! NOTE: SoftwareFPU does not work well on 68LC040 Macs!\n\n");
  418.         }
  419.     }
  420. #endif
  421.     }
  422.  
  423.  
  424. // ---------------------------------------------------------------------
  425. static void DoShutdownMac()
  426. {
  427.     Cooperate(true);
  428.  
  429.     if (gHasAppleEvents)
  430.         SendAEShutdown();
  431.     else
  432.         SysBeep(1);
  433.  
  434.     Cooperate(true);
  435.  
  436. } // DoShutdownMac
  437.  
  438.  
  439. // ---------------------------------------------------------------------
  440. // Play a nifty "finished" sound
  441. static void PlayNotifySound(void)
  442. {
  443. // if you don't have universal headers...
  444. // #define SndListHandle Handle
  445.     SndListHandle    theSndHandle;
  446.     OSErr            anError;
  447.     short            soundResID;
  448.     ResType            soundResType;
  449.     Str255            soundName;
  450.  
  451.     // Get the user's chosen sound ID from prefs
  452.     soundResID = APGet_AllDoneSoundID();
  453.     // load that sound
  454.     theSndHandle = (SndListHandle)GetResource(soundListRsrc, soundResID);
  455.     // play it
  456.     if (theSndHandle)
  457.     {
  458.         if ((**gPrefs2Use_h).progress == eProgDebug)
  459.             {
  460.             GetResInfo((Handle)theSndHandle, &soundResID, &soundResType, soundName);
  461.             p2cstr(soundName);
  462.             printf("\n### Sound playing is '%s' (%ldK bytes)\n\n",
  463.                     soundName, GetResourceSizeOnDisk((Handle)theSndHandle)/1024L);
  464.             }
  465.         anError = noErr;
  466.         // Create a sound channel first time through
  467.         if (gSndChannelPtr == NULL)
  468.             anError = SndNewChannel(&gSndChannelPtr, sampledSynth, 0L, NULL);
  469.         // Normally we can play the sound asynchronously, but if we're automatically
  470.         // quitting, we need to play synchronously, so we don't quit the app
  471.         // while still playing the sound (which simply truncates the sound.)
  472.         if (!anError)
  473.             anError = SndPlay(gSndChannelPtr, theSndHandle, !AppIsQuitting());
  474.     }
  475. } // PlayNotifySound
  476.  
  477.  
  478. // ---------------------------------------------------------------------
  479. // Show an ALL DONE dialog
  480. static void ShowNotifyDialog(void)
  481. {
  482.     if (!gRenderedOK)
  483.         // rendering error
  484.         (void)DisplayModalDialog(143, ok, 0, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
  485.     else
  486.         // completed OK
  487.         (void)DisplayModalDialog(142, ok, 0, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
  488. } // ShowNotifyDialog
  489.  
  490.  
  491.  
  492. // ---------------------------------------------------------------------
  493. // Change the type/creator of the other output file
  494. static void ChangeFileType(void)
  495. {
  496.     OSErr anError;
  497.     FInfo myFileInfo;
  498.  
  499.     // Get file info, so we can change it
  500.     anError = GetFInfo ((StringPtr)gOutFname, gSrcWind_VRefNum, &myFileInfo);
  501.  
  502.     if (anError==noErr)
  503.     {
  504.         switch ((**gPrefs2Use_h).outfileType)
  505.         {
  506.             case eOutfTarga:    // uncompressed targa
  507.             case eOutfTargaC:    // compressed targa
  508.                 myFileInfo.fdType = 'TPIC';
  509.                 myFileInfo.fdCreator = (**gPrefs2Use_h).targaFileCreator;
  510.                 break;
  511.             case eOutfPNG:        // PNG
  512.                 myFileInfo.fdType = 'PNG ';
  513.                 myFileInfo.fdCreator = (**gPrefs2Use_h).targaFileCreator;
  514.                 break;
  515.             case eOutfPPM:        // Unix ppm file
  516.                 myFileInfo.fdType = 'PPGM';
  517.                 myFileInfo.fdCreator = (**gPrefs2Use_h).targaFileCreator;
  518.                 break;
  519.         }
  520.  
  521.         anError = SetFInfo ((StringPtr)gOutFname, gSrcWind_VRefNum, &myFileInfo);
  522.     }
  523. } // ChangeFileType
  524.  
  525.  
  526. // ---------------------------------------------------------------------
  527. // Set up to call the renderer, call it, and clean up after it returns
  528. static void call_main(int argc, char **argv)
  529. {
  530.     char    timeBuffer[128];
  531.  
  532.     dispose_virtual();    // deletes virtual file
  533.     KillOffscreen();    // delete any previous offscreens
  534.  
  535.     Cooperate(true);
  536.     Cooperate(true);
  537.  
  538.     gPrevTickCount = MAC_TICKS;
  539.     gRenderedOK = true;    /* presume that rendering will finish OK */
  540.     // reset our stack-watcher
  541.     gStackMax = 0;
  542.  
  543.     p2cstr(gSrcWind_FileName);
  544.     printf("-- [Start]  File=%s,  Time=%s\n", gSrcWind_FileName, GetDateTimeString(timeBuffer));
  545.     c2pstr((char*)gSrcWind_FileName);
  546.  
  547. #if defined (USE_MEM_HANDLES)
  548.     // turn ON use of temp memory allocation (MEMALLOC.C)
  549. // too extreme for now... need an Application preference... [esp]
  550. //    UseTempMem(TRUE);
  551. #endif
  552.  
  553.     if (setjmp(gSetJmpEnv) == 0)
  554.     {
  555.         // Call the POV-Ray engine to actually render the image
  556.         alt_main(argc, argv);
  557.     }
  558.     // Return here if 'exit()' called
  559.  
  560.     // turn OFF use of temp memory allocation (MEMALLOC.C)
  561. #if defined (USE_MEM_HANDLES)
  562. //    UseTempMem(FALSE);
  563. #endif
  564.  
  565.     if (gRenderedOK && (**gPrefs2Use_h).outfileType > 0)
  566.         ChangeFileType();    /* change type and creator of the output file */
  567.  
  568.     InvalRect_ImageWindow(true);
  569.  
  570.     // how much stack space used?
  571.     if ((**gPrefs2Use_h).progress >= eProgMac)
  572.     {
  573.         printf("-- [Stack] Total Stack space used = %ld bytes\n", gStackMax);
  574.     }
  575.  
  576.     // FINISHED!
  577.     p2cstr(gSrcWind_FileName);
  578.     printf("-- [Finish]  File=%s,  Time=%s\n", gSrcWind_FileName, GetDateTimeString(timeBuffer));
  579.     c2pstr((char*)gSrcWind_FileName);
  580.  
  581.     // Give a quick breath after each render
  582.     // NOTE: Do this before setting gDoingRender back to false, so that the menu
  583.     // allows cmd-period to halt the render, especially during animations.  There
  584.     // window activates too, so call it a few times.
  585.     Cooperate(true);
  586.     Cooperate(true);
  587.     Cooperate(true);
  588.  
  589.     // Whenever we are done rendering a file, pop the status window to the bottom
  590. // now that we have user-controlled auto-scrolling, may not want to do this [esp]
  591. //    p2w_ScrollEnd(gp2wWindow);
  592.  
  593.     gDoingRender = false;
  594. } // call_main
  595.  
  596.  
  597.  
  598. // ---------------------------------------------------------------------
  599. // Force all menus to be disabled
  600. void DisableMenus(void)
  601. {
  602.     int i;
  603.  
  604.     for (i = 1; i < num_of_menus; i++)
  605.         DisableItem(myMenus[i], 0);
  606.  
  607.     // Don't disable about under 7.0, otherwise OS turns OFF ALL MENUS,
  608.     // including help, app, & script menus!
  609.     EnableItem(myMenus[apmn_ID - menu_offset], apmn_about);
  610.  
  611.     HiliteMenu(0);
  612.     DrawMenuBar();
  613. } // DisableMenus
  614.  
  615.  
  616. // ---------------------------------------------------------------------
  617. // Force all menus to be enabled
  618. void EnableMenus(void)
  619. {
  620.     int i;
  621.     for (i = 1; i < num_of_menus; i++)
  622.         EnableItem(myMenus[i], 0);
  623.  
  624.     HiliteMenu(0);
  625.     DrawMenuBar();
  626. } // EnableMenus
  627.  
  628.  
  629.  
  630.  
  631.  
  632. // ---------------------------------------------------------------------
  633. // prompt for which line # to go to, and go to it
  634. #define    kItem_LineNum    4
  635. static void choose_goto_line(void)
  636. {
  637.     short        dummyInt, line_to_go;
  638.     short        itemHit;
  639.     DialogPtr    myDialog;
  640.     Rect        displayRect;
  641.     ControlHandle editTextH;
  642.     char        s1[128];
  643.  
  644.     DisableMenus();
  645.     
  646.     line_to_go = 1; /* for now */
  647.     myDialog = GetNewDialog(150, NULL, (WindowPtr) -1);
  648.     GetDialogItem(myDialog, kItem_LineNum, &dummyInt, (Handle *) &editTextH, &displayRect);
  649.     sprintf(s1, "%d", line_to_go); 
  650.     SetDialogItemText((Handle)editTextH, c2pstr(s1) );
  651.     SelectDialogItemText(myDialog, kItem_LineNum, 0, 32767);
  652.     PositionWindow(myDialog, ewcDoCentering, eSameAsPassedWindow, (WindowPtr)gp2wWindow);
  653.     // set the standard action for OK/cancel buttons
  654.     SetupDefaultDialogButtons(myDialog, ok, cancel);
  655.     ShowWindow(myDialog);
  656.     do
  657.     {
  658.         ModalDialog(GetStdModalFilter(), &itemHit);
  659.     }
  660.     while (itemHit != ok && itemHit != cancel);
  661.     
  662.     if (itemHit == ok)
  663.     {
  664.         GetDialogItemText((Handle)editTextH, (StringPtr)s1);
  665.         p2cstr((StringPtr)s1);
  666.         line_to_go = atoi(s1);
  667.         if (line_to_go<1)
  668.             line_to_go=1;
  669.         else if (line_to_go>32767)
  670.             line_to_go=32767;
  671.     }
  672.     DisposeDialog(myDialog);
  673.     if (itemHit == ok)
  674.         {
  675.         SelectWindow(gSrcWind_Window);
  676.         GotoSrcWindLine(line_to_go);
  677.         }
  678.  
  679.     EnableMenus();
  680. } // choose_goto_line
  681.  
  682.  
  683. // ---------------------------------------------------------------------
  684. // This is what is really called if exit() is called
  685. #define kEXIT_USERBRK    2    // returned from POV-Ray engine if user cancelled
  686. void catch_exit(int n)
  687. {
  688.     // exit(0) is not a syntax error, only jump to line # if <>0
  689.     if (n != 0)
  690.     {
  691.         gRenderedOK = 0;
  692.         // if error & in main file, then go to line number
  693.         if (n != kEXIT_USERBRK) // don't jump to line number if user abort (#2)
  694. /*        if (Include_File_Index == 0) -- no more access to this var, do it always */
  695.         {
  696.             // Show errors at end of status window
  697.             p2w_ScrollEnd(gp2wWindow);
  698.             SelectWindow((WindowPtr)gp2wWindow); // second to front...
  699.             // hilite line number in source window
  700.             GotoSrcWindLine(Token.Token_Line_No+1);
  701.             SelectWindow(gSrcWind_Window);        // front window
  702.         }
  703.     }
  704.  
  705.     // We want to clear out the queue of upcoming files to render if
  706.     // 1. User doesn't want to continue if errors happen
  707.     //    or
  708.     // 2. If it is a user-break.
  709.     if ((APGet_KeepGoingOnErrors() == FALSE) || (n == kEXIT_USERBRK))
  710.         HaltFileQ();
  711.  
  712.     longjmp(gSetJmpEnv, 1);
  713. } // catch_exit
  714.  
  715.  
  716.  
  717. // ---------------------------------------------------------------------
  718. static void DoLookup()
  719. {
  720.     if (FrontWindow() == gSrcWind_Window)
  721.     {
  722.         // First, copy the selection to the clipboard
  723.         SrcWindCopySelToClipboard();
  724.  
  725.         // Now, switch to POV-Reference if it is there
  726.  
  727.         // (POV-Reference is an on-line help reference, which
  728.         // was going to be the stack that came with the book
  729.         // "Ray Tracing for the Macintosh CD", but we didn't
  730.         // get the AppleEvent hooks into the reference.  Feel
  731.         // free to write one as an AppleGuide for example. :-) [esp]
  732.     }
  733. } // DoLookup
  734.  
  735.  
  736. #pragma mark -
  737.  
  738. // ---------------------------------------------------------------------
  739. // set up the POV-Ray engine's argc/argv parameters from file settings
  740. static void SetupRenderArgs(void)
  741. {
  742.     Boolean    allowBitsPerColor;
  743.     char    *s1, *s2;
  744.     char    rawFileName[32];
  745.  
  746.     // --------------------------------
  747.     // create a couple of temporary buffers for building arg-lists
  748.     // --------------------------------
  749.     s1 = (char*)NewPtr(256);
  750.     s2 = (char*)NewPtr(256);
  751.     if (!s1 || !s2)
  752.     {
  753.         (void)DisplayModalDialog(kdlog_GenericFatalErr, ok, 0, "Out of memory building command line",
  754.                                 memFullErr, ewcDoCentering, eMainDevice);
  755.         SetAppQuit();
  756.         return;
  757.     }
  758.  
  759.     // --------------------------------
  760.     // set current directory to that of scene file
  761.     // --------------------------------
  762.  
  763.     SetVol(NULL, gSrcWind_VRefNum);
  764.  
  765.     // --------------------------------------------------------
  766.     // Now start building the parameters
  767.     // --------------------------------------------------------
  768.  
  769.     // --------------------------------
  770.     // argv[0] is always the program name, not used, but cute
  771.     // --------------------------------
  772.     AddArg("POV-Ray");
  773.  
  774.     // --------------------------------
  775.     // get input file and strip off any suffix
  776.     // --------------------------------
  777.     BlockMove(gSrcWind_FileName, rawFileName, gSrcWind_FileName[0]+1); // pascal string copy
  778.     p2cstr((StringPtr)rawFileName); // convert to C string
  779.  
  780.     // --------------------------------
  781.     // set up input file arg
  782.     // --------------------------------
  783.     sprintf(s1, "Input_File_Name=%s", rawFileName);
  784.     AddArg(s1);
  785.     
  786.     // --------------------------------
  787.     // set up raw output file
  788.     // --------------------------------
  789.     {
  790.         short    theLen, suffixLen;
  791.         char    *dotPtr;
  792.         // look for .POV suffix on input file name
  793.         dotPtr = strrchr(rawFileName, '.');
  794.         theLen = strlen(rawFileName);
  795.         if (dotPtr != NULL)
  796.         {
  797.             *dotPtr = '\0'; // terminate string here, on the dot
  798.         }
  799.         // Also make sure we have at least 5 or 4+5 characters available on end now,
  800.         // 5 for the ".pict" and optionally 4 more for the animation digits
  801.         theLen = strlen(rawFileName);
  802.         if ((**gPrefs2Use_h).doAnimation)
  803.             suffixLen = 4+5;    // add "nnnn.pict"
  804.         else
  805.             suffixLen = 5;        // add ".pict"
  806.  
  807.         if (theLen+suffixLen > 31) // max file name length
  808.         {
  809.             rawFileName[31-suffixLen] = 0; // terminate string here
  810.         }
  811.         // add frame value to filename if animating
  812.         if ((**gPrefs2Use_h).doAnimation)
  813.         {
  814.             sprintf(s1, "%04d", GetCurrFrameVal());
  815.             strcat(rawFileName, s1);
  816.         }
  817.     }
  818.  
  819.     // --------------------------------
  820.     // output file name (PICT)
  821.     // --------------------------------
  822.  
  823.     // Put raw file name into pict file
  824.     strcpy((char*)gPictFname, rawFileName);
  825.     // add suffix
  826.     strcat((char*)gPictFname, ".pict");
  827.     // convert to Pascal string
  828.     c2pstr((char*)gPictFname);    
  829.  
  830.     // --------------------------------
  831.     // output file name/type (other)
  832.     // --------------------------------
  833.  
  834.     // If image is too big for PICT & user is only saving to pict, force other file output!
  835.     // NOTE: This is a grody hack until we fix VIB to work with big images! [esp]
  836.     if (gTooBigForPICT && ((**gPrefs2Use_h).outfileType == eOutfNone))
  837.         {
  838.         (**gPrefs2Use_h).outfileType = eOutfPNG;
  839.         }
  840.     
  841.     // Put raw file name into other output filename
  842.     strcpy((char*)gOutFname, rawFileName);
  843.  
  844.     // add file type suffix (pict, png, targa or ppm)
  845.     allowBitsPerColor = FALSE; // until disproved
  846.     switch ((**gPrefs2Use_h).outfileType)
  847.     {
  848.         case eOutfNone:    // PICT only
  849.             AddArg("Output_To_File=off");
  850.             allowBitsPerColor = TRUE;    // PICT
  851.             break;
  852.         case eOutfTarga:    // uncompressed targa
  853.             AddArg("Output_File_Type=T");
  854.             strcat((char*)gOutFname, ".tga");
  855.             break;
  856.         case eOutfTargaC:    // compressed targa
  857.             AddArg("Output_File_Type=C");
  858.             strcat((char*)gOutFname, ".tga");
  859.             break;
  860.         case eOutfPNG:        // PNG
  861.             AddArg("Output_File_Type=N");
  862.             strcat((char*)gOutFname, ".png");
  863.             allowBitsPerColor = TRUE;
  864.             break;
  865.         case eOutfPPM:        // Unix ppm file
  866.             AddArg("Output_File_Type=P");
  867.             strcat((char*)gOutFname, ".ppm");
  868.             break;
  869.         default:
  870.             strcat((char*)gOutFname, ".<?>");
  871.             break;
  872.     }
  873.     // write output file name arg
  874.     sprintf(s1, "Output_File_Name=%s", (char*)gOutFname);
  875.     AddArg(s1);
  876.     // convert to Pascal string
  877.     c2pstr((char*)gOutFname);    
  878.  
  879.     // --------------------------------
  880.     // bits per color for certain image file types (PNG/PICT)
  881.     // --------------------------------
  882.     if (allowBitsPerColor)
  883.         {
  884.         sprintf(s1, "Bits_Per_Color=%d", (int)(**gPrefs2Use_h).bitsPerColor);
  885.         AddArg(s1);
  886.         }
  887.  
  888.     // --------------------------------
  889.     // Do alpha channel?
  890.     // --------------------------------
  891.     sprintf(s1, "Output_Alpha=%d", (**gPrefs2Use_h).doAlphaChannel);
  892.     AddArg(s1);
  893.  
  894.     // --------------------------------
  895.     // display format always on for Mac
  896.     // (This turns on the display calls & image window)
  897.     // --------------------------------
  898.     AddArg("Display=on");
  899.  
  900.     // --------------------------------
  901.     // exit enable on, but we breathe via COOPERATE too
  902.     // (this is mostly turned on for aesthetics, so that the
  903.     // status window shows it ON)
  904.     // --------------------------------
  905.     AddArg("Test_Abort=on");
  906.  
  907.     // --------------------------------
  908.     // pause for keypress on exit (In the Mac world?  NOT!)
  909.     // --------------------------------
  910.     AddArg("Pause_When_Done=off");
  911.  
  912.     // --------------------------------
  913.     // Min Language Syntax Version
  914.     // --------------------------------
  915.     if ((**gPrefs2Use_h).languageVersion < eMaxLangVersion)
  916.         {
  917.         sprintf(s1, "Version=%d", (int)(**gPrefs2Use_h).languageVersion);
  918.         AddArg(s1);
  919.         }
  920.  
  921.     // --------------------------------
  922.     // rendering Quality value
  923.     // --------------------------------
  924.     sprintf(s1, "Quality=%d", (**gPrefs2Use_h).renderQuality);
  925.     AddArg(s1);
  926.  
  927.     // --------------------------------
  928.     // radiosity Quality flag
  929.     // --------------------------------
  930.     if ((**gPrefs2Use_h).radQuality > 0)
  931.         AddArg("Radiosity=on");
  932.  
  933.     // --------------------------------
  934.     // set clock variable value
  935.     // --------------------------------
  936.     if ((**gPrefs2Use_h).doAnimation)
  937.         {
  938.         sprintf(s1, "Clock=%g", GetCurrClockVal());
  939.         AddArg(s1);
  940.         }
  941.  
  942.     // --------------------------------
  943.     // set histogram info
  944.     // --------------------------------
  945.     if ((**gPrefs2Use_h).doHistogram)
  946.         {
  947.         sprintf(s1, "Histogram_Type=%c", (**gPrefs2Use_h).histogramType);
  948.         AddArg(s1);
  949.  
  950.         // Put raw file name into histogram output filename
  951.         strcpy((char*)s2, rawFileName);
  952.  
  953.         // get file type suffix (targa or ppm)
  954.         switch ((**gPrefs2Use_h).histogramType)
  955.             {
  956.             case eOutfTarga:    // uncompressed targa
  957.                 AddArg("Histogram_Type=T");
  958.                 strcpy(s2, ".tga");
  959.                 break;
  960.             case eOutfTargaC:    // compressed targa
  961.                 AddArg("Histogram_Type=C");
  962.                 strcpy(s2, ".tga");
  963.                 break;
  964.             case eOutfPNG:        // PNG
  965.                 AddArg("Histogram_Type=N");
  966.                 strcpy(s2, "png");
  967.                 break;
  968.             case eOutfPPM:        // Unix ppm file
  969.                 AddArg("Histogram_Type=P");
  970.                 strcpy(s2, "ppm");
  971.                 break;
  972.             case eOutfNone:
  973.             default:
  974.                 AddArg("Histogram_Type=T");
  975.                 strcpy(s2, "tga");
  976.                 break;
  977.             }
  978.  
  979.         sprintf(s1, "Histogram_Grid_Size=%d.%d",
  980.                     (**gPrefs2Use_h).histogramXSize,
  981.                     (**gPrefs2Use_h).histogramYSize);
  982.         AddArg(s1);
  983.         sprintf(s1, "Histogram_File=%s.hist.%s", rawFileName, s2); // WARNING: This fname could be to long!
  984.         AddArg(s1);
  985.         }
  986.  
  987.     // --------------------------------
  988.     // show render progress messages
  989.     // --------------------------------
  990.     switch ((**gPrefs2Use_h).progress)
  991.     {
  992.         case eProgDebug:    // used by Mac only
  993.             // fall through to set verbose ON as well
  994.  
  995.         case eProgVerbose:
  996.             AddArg("Verbose=on");
  997.             break;
  998.  
  999.         case eProgNone:
  1000.         case eProgMac:
  1001.             // Minimal is Mac debugs, not core debugs, and the Mac code
  1002.             // will show its debugs when eProgMac is on.
  1003.             AddArg("Verbose=off");
  1004.             break;
  1005.     }
  1006.  
  1007.     // --------------------------------
  1008.     // render output size
  1009.     // --------------------------------
  1010.     sprintf(s1, "Width=%d", (**gPrefs2Use_h).imageWidth);
  1011.     AddArg(s1);
  1012.  
  1013.     sprintf(s1, "Height=%d", (**gPrefs2Use_h).imageHeight);
  1014.     AddArg(s1);
  1015.  
  1016.     // --------------------------------
  1017.     // actual render rectangle
  1018.     // --------------------------------
  1019.     if ((**gPrefs2Use_h).selectionArea.top > 1)
  1020.         {
  1021.         sprintf(s1, "Start_Row=%d", (**gPrefs2Use_h).selectionArea.top);
  1022.         AddArg(s1);
  1023.         }
  1024.  
  1025.     sprintf(s1, "End_Row=%d", (**gPrefs2Use_h).selectionArea.bottom);
  1026.     AddArg(s1);
  1027.  
  1028.     if ((**gPrefs2Use_h).selectionArea.left > 1)
  1029.         {
  1030.         sprintf(s1, "Start_Column=%d", (**gPrefs2Use_h).selectionArea.left);
  1031.         AddArg(s1);
  1032.         }
  1033.  
  1034.     sprintf(s1, "End_Column=%d", (**gPrefs2Use_h).selectionArea.right);
  1035.     AddArg(s1);
  1036.  
  1037.     // --------------------------------
  1038.     // anti-aliasing
  1039.     // --------------------------------
  1040.     if ((**gPrefs2Use_h).doAntialias)
  1041.     {
  1042.         AddArg("Antialias=on");
  1043.         sprintf(s1, "Antialias_Threshold=%g", (**gPrefs2Use_h).antialiasThreshold);
  1044.         AddArg(s1);
  1045.  
  1046.  
  1047.         // Anti-aliasing Sampling method (1 or 2)
  1048.         sprintf(s1, "Sampling_Method=%d", (**gPrefs2Use_h).antialiasMethod);
  1049.         AddArg(s1);
  1050.  
  1051.         // Anti-aliasing Depth
  1052.         sprintf(s1, "Antialias_Depth=%d", (**gPrefs2Use_h).antialiasDepth);
  1053.         AddArg(s1);
  1054.  
  1055.         // Anti-aliasing Jitter Scale
  1056.         sprintf(s1, "Jitter_Amount=%g", (**gPrefs2Use_h).antiJitterScale);
  1057.         AddArg(s1);
  1058.     }
  1059.     else
  1060.         AddArg("Antialias=off");
  1061.  
  1062.     // --------------------------------
  1063.     // Mosaic preview mode
  1064.     // --------------------------------
  1065.     if ((**gPrefs2Use_h).previewStart > 0)
  1066.     {
  1067.         sprintf(s1, "Preview_Start_Size=%d", 1<<((**gPrefs2Use_h).previewStart-1));
  1068.         AddArg(s1);
  1069.         sprintf(s1, "Preview_End_Size=%d", 1<<((**gPrefs2Use_h).previewEnd-1));
  1070.         AddArg(s1);
  1071.     }
  1072.  
  1073.     // --------------------------------
  1074.     // enable/disable bounding slabs
  1075.     // --------------------------------
  1076.     if ((**gPrefs2Use_h).doBoundSlabs)
  1077.     {
  1078.         // set min objects to start auto-bounding
  1079.         sprintf(s1, "Bounding_Threshold=%d", (**gPrefs2Use_h).boundSlabThreshold);
  1080.         AddArg(s1);
  1081.     }
  1082.  
  1083.     // --------------------------------
  1084.     // enable/disable field rendering
  1085.     // --------------------------------
  1086.     if ((**gPrefs2Use_h).doFieldRender)
  1087.     {
  1088.         // set min objects to start auto-bounding
  1089.         AddArg("Field_Render=on");
  1090.         // set which scanline to start on
  1091.         if ((**gPrefs2Use_h).doOddField)
  1092.             AddArg("Odd_Field=on");
  1093.         else
  1094.             AddArg("Odd_Field=off");
  1095.     }
  1096.     else
  1097.         AddArg("Field_Render=off");
  1098.  
  1099.     // --------------------------------
  1100.     // Split unions
  1101.     // --------------------------------
  1102.     sprintf(s1, "Split_Unions=%d", (**gPrefs2Use_h).doSplitUnions);    // on/off
  1103.     AddArg(s1);
  1104.  
  1105.     // --------------------------------
  1106.     // Vista/Light Buffers
  1107.     // --------------------------------
  1108.     sprintf(s1, "Vista_Buffer=%d", (**gPrefs2Use_h).doVistaBuffer);    // on/off
  1109.     AddArg(s1);
  1110.  
  1111.     sprintf(s1, "Light_Buffer=%d", (**gPrefs2Use_h).doLightBuffer);    // on/off
  1112.     AddArg(s1);
  1113.  
  1114.     sprintf(s1, "Draw_Vistas=%d", (**gPrefs2Use_h).doVistaDraw);    // on/off
  1115.     AddArg(s1);
  1116.  
  1117.     sprintf(s1, "Remove_Bounds=%d", (**gPrefs2Use_h).removeBounds);    // on/off
  1118.     AddArg(s1);
  1119.  
  1120.     // --------------------------------
  1121.     // continue with previous targa file
  1122.     // --------------------------------
  1123.     sprintf(s1, "Continue_Trace=%d", (**gPrefs2Use_h).continueTarga);    // on/off
  1124.     AddArg(s1);
  1125.  
  1126.     // --------------------------------
  1127.     // Output buffer size
  1128.     // --------------------------------
  1129.     if ((**gPrefs2Use_h).outfileBuffSize)
  1130.         {
  1131.         sprintf(s1, "Buffer_Size=%d", (**gPrefs2Use_h).outfileBuffSize); // in KBytes
  1132.         AddArg(s1);
  1133.         }
  1134.  
  1135.     // --------------------------------
  1136.     // Add +L options for library paths
  1137.     // convert volume name to vref for making full path
  1138.     // --------------------------------
  1139.     VolName2VRef((**gAppPrefs_h).includeDirFSSpec.name,
  1140.                 &(**gAppPrefs_h).includeDirFSSpec.vRefNum);
  1141.     PathNameFromDirID((**gAppPrefs_h).includeDirFSSpec.parID, (**gAppPrefs_h).includeDirFSSpec.vRefNum, s2);
  1142.     // whack trailing colon, POV-Ray wants to add it!
  1143.     if (s2[strlen(s2)-1] == ':')
  1144.         s2[strlen(s2)-1] = '\0';
  1145.     sprintf(s1, "Library_Path=%s", s2);
  1146.     AddArg(s1);
  1147.  
  1148.     // --------------------------------
  1149.     // Create INI output file
  1150.     // --------------------------------
  1151.     if ((**gPrefs2Use_h).doCreateINI)
  1152.     {
  1153.         sprintf(s1, "Create_Ini=%s.ini", rawFileName);
  1154.         AddArg(s1);
  1155.     }
  1156.  
  1157.     // --------------------------------
  1158.     // Is there a file-specific INI file to read in?
  1159.     // --------------------------------
  1160.  
  1161.     // If there is an INI file in this folder with the scene file, tell POV to read it
  1162.     sprintf(s2, "%s.ini", rawFileName);
  1163.     if (File_Exists(s2))
  1164.         {
  1165.         sprintf(s1, "Include_Ini=%s", s2);
  1166.         AddArg(s1);
  1167.         }
  1168.  
  1169.     // --------------------------------
  1170.     // Clean up
  1171.     // --------------------------------
  1172.  
  1173.     // flush any pending writes prior to rendering
  1174.     FlushVol(NULL, gSrcWind_VRefNum);
  1175.  
  1176.     Stop_Flag = 0;
  1177.     gDoingRender = true;
  1178.  
  1179.     // All done with temporary string buffers
  1180.     if (s1)
  1181.         DisposePtr((Ptr)s1);
  1182.     if (s2)
  1183.         DisposePtr((Ptr)s2);
  1184.  
  1185.     // calculate current CPU timeslice setting
  1186.     CalcCpuReleaseTicks(true);
  1187.  
  1188. } // SetupRenderArgs
  1189.  
  1190.  
  1191.  
  1192. // ---------------------------------------------------------------------
  1193. // Set all menu items availability depending on application states
  1194. static void SetItemEnable(MenuHandle theMenu, short theItem, Boolean isEnabled)
  1195. {
  1196.     if (isEnabled)
  1197.         EnableItem(theMenu, theItem);
  1198.     else
  1199.         DisableItem(theMenu, theItem);
  1200. } // SetItemEnable
  1201.  
  1202.  
  1203.  
  1204.  
  1205. // ---------------------------------------------------------------------
  1206. // Prompt user "OK to Quit?"
  1207. static void ask_about_quit(void)
  1208. {
  1209.     short        itemHit;
  1210.  
  1211.     if    (    gDoingRender &&
  1212.             (    ((**gPrefs2Use_h).outfileType == eOutfTarga)
  1213.             ||    ((**gPrefs2Use_h).outfileType == eOutfTargaC)
  1214.             ||    ((**gPrefs2Use_h).outfileType == eOutfPNG) )
  1215.         )
  1216.     {
  1217.         // ok to quit?
  1218.         itemHit = DisplayModalDialog(137, ok, cancel, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
  1219.         if (itemHit == ok)
  1220.         {
  1221.             Stop_Flag = true;
  1222.             SetAppQuit();
  1223.         }
  1224.     }
  1225.     else
  1226.     {
  1227.         Stop_Flag = true;
  1228.         SetAppQuit();
  1229.     }
  1230. } // ask_about_quit
  1231.  
  1232.  
  1233.  
  1234. // ---------------------------------------------------------------------
  1235. // Prompt user, "OK to Stop Rendering?"
  1236. static void ask_about_stop(void)
  1237. {
  1238.     short        itemHit;
  1239.  
  1240.     if    (    ((**gPrefs2Use_h).outfileType == eOutfTarga)
  1241.         || ((**gPrefs2Use_h).outfileType == eOutfTargaC)
  1242.         || ((**gPrefs2Use_h).outfileType == eOutfPNG))
  1243.         // stopped, to continue, use targa/png..
  1244.         itemHit = DisplayModalDialog(135, ok, 0, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
  1245.     else
  1246.         // no targa, OK to stop?
  1247.         itemHit = DisplayModalDialog(134, ok, cancel, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
  1248.  
  1249.     if (itemHit == ok)
  1250.     {
  1251.         // For now, just set the STOP flag...
  1252.         Stop_Flag = 1;
  1253.     }
  1254. } // ask_about_stop
  1255.  
  1256.  
  1257.  
  1258. // ---------------------------------------------------------------------
  1259. // Pause rendering until user continues
  1260. static void pause_it(void)
  1261. {
  1262.  
  1263.     if (gPaused == 1)
  1264.         gPaused = 2;    // already recursively paused, so now un-pause
  1265.     else
  1266.     {    // prepare to pause
  1267.         gPaused = 1;
  1268.         DisableMenus();
  1269.  
  1270.         // re-enable just the pause menu item
  1271.         EnableItem(myMenus[rnmn_ID - menu_offset], 0);
  1272.         EnableItem(myMenus[rnmn_ID - menu_offset], rnmn_pause);
  1273.         CheckItem(myMenus[rnmn_ID - menu_offset], rnmn_pause, 1);
  1274.         DrawMenuBar();
  1275.  
  1276.         // pause loop..
  1277.         do
  1278.         {
  1279.             // allow user to do stuff..
  1280.             Cooperate(true);
  1281.             // until they pick pause again (2)
  1282.         } while ((Stop_Flag == 0) && (gPaused != 2));
  1283.     
  1284.         // done pausing, restore & return
  1285.         EnableMenus();
  1286.         CheckItem(myMenus[rnmn_ID - menu_offset], rnmn_pause, 0);
  1287.         gPaused = 0;
  1288.     }
  1289. } // pause_it
  1290.  
  1291.  
  1292.  
  1293. // ---------------------------------------------------------------------
  1294. // Handle any window's Activate event
  1295. static void HandleActivate(WindowPtr theWindow, Boolean becomingActive)
  1296. {
  1297.     if (becomingActive)        // ACTIVATE
  1298.     {
  1299.         if (theWindow == gSrcWind_Window)
  1300.         {
  1301.             DoActivateEditor(becomingActive);
  1302.         }
  1303.         else if ((theWindow == (WindowPtr)gp2wWindow) && (gp2wWindow))
  1304.         {
  1305.             p2w_DoActivate(gp2wWindow, becomingActive);
  1306.         }
  1307.         else if (theWindow == gImageWindowPtr)
  1308.         {
  1309.         }
  1310.     }
  1311.     else                    // DE-ACTIVATE
  1312.     {
  1313.         if (theWindow == gSrcWind_Window)
  1314.         {
  1315.             DoActivateEditor(becomingActive);
  1316.         }
  1317.         else if ((theWindow == (WindowPtr)gp2wWindow) && (gp2wWindow))
  1318.         {
  1319.             p2w_DoActivate(gp2wWindow, becomingActive);
  1320.         }
  1321.         else if (theWindow == gImageWindowPtr)
  1322.         {
  1323.         }
  1324.     }
  1325. } // HandleActivate
  1326.  
  1327.  
  1328.  
  1329.  
  1330. // ---------------------------------------------------------------------
  1331. // Display additional credits on POV-Ray startup
  1332. void PrintMacCredits(void)
  1333. {
  1334.     char    appVers[32];
  1335.  
  1336.     GetAppVersionPString(1, (StringPtr)appVers);
  1337.     p2cstr((StringPtr)appVers);
  1338.     fprintf (stderr,"\n");
  1339.     fprintf (stderr,"POV-Ray version %s [%s]\n\n", appVers,COMPILER_VER);
  1340.  
  1341.     fprintf (stderr,"This Macintosh implementation of POV-Ray is brought to you by:\n");
  1342.     fprintf (stderr,"  Eduard Schwan\n");
  1343.  
  1344.     fprintf (stderr,"Version 3.0.2 Editor 'undo' support code by:\n");
  1345.     fprintf (stderr,"  Thorsten Froehlich, CIS 106325,3677\n");
  1346.  
  1347.     fprintf (stderr,"Past Macintosh development help:\n");
  1348.     fprintf (stderr,"  David Harr      Jim Nitchals\n");
  1349.  
  1350. #if defined(powerc) || defined (__powerc)
  1351.     fprintf (stderr,"Past Power Macintosh development guidance:\n");
  1352.     fprintf (stderr,"  David Harr      Paul Snively     Monroe Williams\n");
  1353. #endif
  1354.  
  1355.     fprintf (stderr,"----------------------------------------------------------------------\n\n");
  1356. } // PrintMacCredits
  1357.  
  1358.  
  1359.  
  1360. // ---------------------------------------------------------------------
  1361. // Moves and sizes the window passed to fit the Rect passed.
  1362. // No checking is done to see that it fits on a screen.
  1363. static void MoveSizeWindow(WindowPtr pWindow, Rect * pWindRect)
  1364. {
  1365.     // position & size the window
  1366.     MoveWindow(pWindow, pWindRect->left, pWindRect->top, false);
  1367.     // oh the grodiest hack for now... someday, all windows will be equal!
  1368.     // until then, we gotta put up with the skanky editor window.
  1369.     if (pWindow == gSrcWind_Window)
  1370.         MyResizeWindow(pWindow, pWindRect->right - pWindRect->left, pWindRect->bottom - pWindRect->top);
  1371.     else
  1372.         SizeWindow(pWindow, pWindRect->right - pWindRect->left, pWindRect->bottom - pWindRect->top, false);
  1373. } // MoveSizeWindow
  1374.  
  1375.  
  1376. // ---------------------------------------------------------------------
  1377. // positions and displays a new source window.
  1378. static void OpenNewSourceWindow(void)
  1379. {
  1380.     // set up window title to be file name
  1381.     SetWTitle(gSrcWind_Window, gSrcWind_FileName);
  1382.  
  1383.     // Set Image window to saved position, shown later when render starts
  1384.     MoveSizeWindow(gImageWindowPtr, &(**gFilePrefs_h).imageWind_pos);
  1385.  
  1386.     // Set Source window position to saved position & show it
  1387.     MoveSizeWindow(gSrcWind_Window, &(**gFilePrefs_h).srcWind_pos);
  1388.  
  1389.     // Make sure it is visible
  1390.     ShowWindow(gSrcWind_Window);
  1391.     // reset the selection to beginning of file
  1392.     // It would be nice to remember users last selection/insertion point & restore it here...
  1393.     // but I'd like to use the MPW/BBEdit 'MPSR' resource for this (as well as window pos.)
  1394.     SrcWindSetSelect(0, 0);
  1395.     // force editor to scroll to selection
  1396.     ShowSelect();
  1397.     // pull new source window to front... but...
  1398.     SelectWindow(gSrcWind_Window);
  1399.     // open up behind other windows if splash screen or MModal dialog is up
  1400.     if (SplashScreenShown())
  1401.         SelectSplashScreen();    // pull splash screen back to front
  1402.     else if (IsMModalDialogDisplayed())
  1403.         SelectWindow(GetCurrMModalDialog());    // pull modal to front
  1404.  
  1405.     gSrcWind_visible = TRUE;
  1406. } // OpenNewSourceWindow
  1407.  
  1408.  
  1409. // ---------------------------------------------------------------------
  1410. // Convert a vref/dirID into a magic vref (working dir)
  1411. static OSErr MyDirID2VrefNum(short vRefNum, long dirID, short *theWDVrefNumPtr)
  1412. {
  1413.     OSErr            anError;
  1414.  
  1415.     // Open a Working directory for ourselves.  Note that we leave
  1416.     // it open forever (just like SFGetFile does.)  This is supposed
  1417.     // to be kosher, the Finder is to clean up after us when we quit!?
  1418.     anError = OpenWD(vRefNum, dirID, kAppSignature, theWDVrefNumPtr);
  1419.     return anError;
  1420. } // MyDirID2VrefNum
  1421.  
  1422.  
  1423.  
  1424. // ---------------------------------------------------------------------
  1425. // General entry to open a source file for editing
  1426. void OpenTextFile(Str255 fn, short vRef, long dirID, Boolean UseDirID)
  1427. {
  1428.     short    fRefNum, vRefNum;
  1429.     int        errcode = noErr;
  1430.  
  1431.     // close any existing file first
  1432.     CloseMyWindow();
  1433.  
  1434.     // If ODOC, find working dir from vref/dirID so we can use FSOpen etc.
  1435.     if (UseDirID)
  1436.     {
  1437.         // convert vref/dirID into WD vrefnum for later FSOpen and SetVol calls
  1438.         errcode = MyDirID2VrefNum(vRef, dirID, &vRefNum);
  1439.     }
  1440.     else
  1441.     {
  1442.         vRefNum = vRef;
  1443.     }
  1444.  
  1445.     if (errcode==noErr)
  1446.         errcode = FSOpen(fn, vRefNum, &fRefNum);
  1447.     if (errcode==noErr)
  1448.     {
  1449.         gSrcWind_dirty = FALSE; // may turn ON in ReadFile
  1450.         errcode = ReadFile(fRefNum);
  1451.         FSClose(fRefNum);    /* and ignore close errors */
  1452.         if (errcode == noErr) 
  1453.         {
  1454.             pStrCopy(fn, gSrcWind_FileName);
  1455.             gSrcWind_VRefNum = vRefNum;
  1456.             FilePrefs_Read(gSrcWind_VRefNum, gSrcWind_FileName);
  1457.             OpenNewSourceWindow();
  1458.         }
  1459.         else if (errcode == 999)
  1460.             FileError("\pFile too large to be edited: ", fn);
  1461.         else
  1462.             FileError("\pError reading ", fn);
  1463.     }
  1464.     else
  1465.         FileError("\pError opening ", fn);
  1466.  
  1467. } // OpenTextFile
  1468.  
  1469.  
  1470.  
  1471. // ---------------------------------------------------------------------
  1472. // Save the status window text into a new text file
  1473. static int Save_StatusWindow(void)
  1474. {
  1475.     OSErr    ioError;
  1476.     char    hstate;
  1477.     short    vRef = 0;
  1478.     short    refNum;
  1479.     char    fn[] = "\pPOV-Ray Status.Window";
  1480.  
  1481.     ShowWatchCursor(); // could take a little while..
  1482.  
  1483.     ioError = FSDelete((StringPtr)fn, vRef); 
  1484.     ioError = Create((StringPtr)fn, vRef, 'ttxt', 'TEXT');
  1485.     if ((ioError == noErr) || (ioError == dupFNErr))
  1486.         ioError = FSOpen((StringPtr)fn, vRef, &refNum);
  1487.     if (ioError)
  1488.     {
  1489.         ShowArrowCursor(); // all done
  1490.         FileError("\pError creating Status file ", (StringPtr)fn);
  1491.         return (0);
  1492.     }
  1493.     else
  1494.     {
  1495.         hstate = HGetState((**gp2wWindow->p2wTEHandle).hText);
  1496.         HLock((**gp2wWindow->p2wTEHandle).hText);
  1497.  
  1498.         if (WriteFile(refNum, (*(**gp2wWindow->p2wTEHandle).hText),
  1499.                         (long)(**gp2wWindow->p2wTEHandle).teLength))
  1500.             FileError("\pError writing file ", (StringPtr)fn);
  1501.  
  1502.         HSetState((**gp2wWindow->p2wTEHandle).hText, hstate);
  1503.  
  1504.         FSClose(refNum);
  1505.  
  1506.         ShowArrowCursor(); // all done
  1507.         return(1);
  1508.     }
  1509. } // Save_StatusWindow
  1510.  
  1511.  
  1512.  
  1513. // ---------------------------------------------------------------------
  1514. // Done rendering, beep or auto-shutdown if requested
  1515. static void notify_user(void)
  1516. {
  1517.     Boolean        doFeedback = false;
  1518.     Boolean        doBeep = false;
  1519.     Boolean        doDialog = false;
  1520.     Boolean        doQuit = false;
  1521.     Boolean        doShutdown = false;
  1522.  
  1523.     if (gRenderedOK)
  1524.         SetCustomPalette(!gInBackground);
  1525.  
  1526.     /* If the image rendered OK and shutdown was requested, then shut down. */
  1527.     if (gRenderedOK)
  1528.     {
  1529.         switch (APGet_AllDoneNotify())
  1530.         {
  1531.             case eDone_Quiet:    // don't notify at all when done
  1532.                 break;
  1533.             case eDone_Beep:    // do noise
  1534.                 doBeep = true;
  1535.                 break;
  1536.             case eDone_Dialog:    // do dialog
  1537.                 doDialog = true;
  1538.                 break;
  1539.             case eDone_BnD:        // do noise & dialog
  1540.                 doBeep = true;
  1541.                 doDialog = true;
  1542.                 break;
  1543.             case eDone_Quit:    // quit app
  1544.                 doQuit = true;
  1545.                 break;
  1546.         } // switch
  1547.  
  1548.         // check for shutting down when done
  1549.         if (APGet_ShutDownWhenDone())
  1550.         {
  1551.                 doQuit = true;
  1552.                 doShutdown = true;
  1553.         }
  1554.     }
  1555.  
  1556.     // Set our quit flag
  1557.     if (doQuit)
  1558.         {
  1559.         Save_StatusWindow();
  1560.         SetAppQuit();
  1561.         }
  1562.  
  1563.     // get everyone's attention...
  1564.     if (doBeep)
  1565.         PlayNotifySound();
  1566.     if (doDialog)
  1567.         ShowNotifyDialog();
  1568.     if (doShutdown)
  1569.         DoShutdownMac();
  1570.  
  1571. } // notify_user
  1572.  
  1573.  
  1574.  
  1575. // ---------------------------------------------------------------------
  1576. // create and display a new empty source window
  1577. void DoFile_New(void)
  1578. {
  1579.     // close any existing file
  1580.     CloseMyWindow();
  1581.  
  1582.     // set up untitled
  1583.     SetUpFiles();
  1584.  
  1585.     // new file gets default prefs
  1586.     **gFilePrefs_h = **gDefltFilePrefs_h;
  1587.  
  1588.     OpenNewSourceWindow();
  1589.     gSrcWind_dirty = FALSE;
  1590.  
  1591. } // DoFile_New
  1592.  
  1593.  
  1594.  
  1595. // ---------------------------------------------------------------------
  1596. // Prompt user for a source file, and open it into source window
  1597. void DoFile_Open(void)
  1598. {
  1599.     short    vRef = 0;
  1600.     Str255     fn;
  1601.  
  1602.     if (OldFile(fn, &vRef))
  1603.     {
  1604.         OpenTextFile(fn, vRef, 0L, false/*!UseDirID*/);    
  1605.     }
  1606. } // DoFile_Open
  1607.  
  1608.  
  1609.  
  1610. // ---------------------------------------------------------------------
  1611. // Set up, call the renderer, and notify user when done
  1612. static void DoRendering(void)
  1613. {
  1614.     Boolean    stillDoingAnimation;
  1615.     long    start_ticks;
  1616.     short    animFrameNumber;
  1617.  
  1618.     if (gSrcWind_dirty)
  1619.         if (DoFile(fmn_save))
  1620.             ;
  1621.  
  1622.     gInAnimationLoop = (**gPrefs2Use_h).doAnimation;
  1623.     gAnimRec = (**gPrefs2Use_h).animRec;
  1624.     SetCurrFrameVal(&gAnimRec, gAnimRec.frameValS);
  1625.     stillDoingAnimation = gInAnimationLoop;
  1626.     gAutoShutdown = APGet_ShutDownWhenDone();
  1627.  
  1628.  
  1629.     // pull status window to front (not user-friendly, but user-requested!)
  1630.     SelectWindow((WindowPtr)gp2wWindow);
  1631.  
  1632.     do    {
  1633.         // init the fake argc/argv buffers
  1634.         InitArgv();
  1635.  
  1636.         SetupRenderArgs();
  1637.  
  1638.         if ( stillDoingAnimation && ((**gPrefs2Use_h).progress >= eProgMac) )
  1639.         {
  1640.             printf("-- [Animation] StartFrame=%d,  EndFrame=%d, CurrFrame=%d, CurrClock=%g)\n",
  1641.                 gAnimRec.frameValS, gAnimRec.frameValE, GetCurrFrameVal(), GetCurrClockVal());
  1642.         }
  1643.  
  1644.         start_ticks = MAC_TICKS;
  1645.  
  1646.         // Do the real POV-Ray work now
  1647.         if (!Stop_Flag && !AppIsQuitting())
  1648.             call_main(my_argc, my_argv);
  1649.  
  1650.         // all done with the argc/argv buffers
  1651.         DestroyArgv();
  1652.  
  1653.         // write PICT file with current name.PICT
  1654.         if    (
  1655.                 (APGet_AutoSaveImage() || gAutoShutdown
  1656.                     || gInAnimationLoop || gDoingBatchODOCs)
  1657.                 && gRenderedOK && !Stop_Flag && !AppIsQuitting()
  1658.             )
  1659.         {
  1660.             // set up frame # suffix (if any)
  1661.             if (gInAnimationLoop)
  1662.                 animFrameNumber = GetCurrFrameVal();
  1663.             else
  1664.                 animFrameNumber = kNoAnimSuffix;
  1665.             // save the image
  1666.             SaveOutputFile(false, gtheSCComponent);
  1667.         }
  1668.  
  1669.         // next frame
  1670.         if (gInAnimationLoop)
  1671.             stillDoingAnimation = IncToNextFrame(&gAnimRec);
  1672.  
  1673.     } while (stillDoingAnimation && !Stop_Flag && !AppIsQuitting());
  1674.  
  1675.     gInAnimationLoop = false;
  1676.  
  1677.     /*
  1678.     If POV wasn't prematurely stopped, and if it is not in the middle of
  1679.     multiple renders, then call the notification procedure.
  1680.     */
  1681.     if    (!Stop_Flag && (FileQ_NumItems() == 0))
  1682.         notify_user();
  1683.  
  1684.     gBeginRendering = false; // all done for now
  1685.     gDoingBatchODOCs = false; // in case it was on from odoc
  1686.  
  1687.     if (APGet_AllDoneNotify() == eDone_Quit)
  1688.         SetAppQuit();
  1689. } // DoRendering
  1690.  
  1691.  
  1692.  
  1693.  
  1694. // ---------------------------------------------------------------------
  1695. // Open a source file, render it, save the image PICT, and close the source file
  1696. static void BatchProcessOneFile(FSSpec    *pFile)
  1697. {
  1698.     gDoingBatchODOCs = true; // postpone other ODOCs until done with this one!
  1699.  
  1700.     OpenTextFile(pFile->name, pFile->vRefNum, pFile->parID, true/*UseDirID*/);
  1701.     DoRendering();
  1702.     DoFile(fmn_close);
  1703.  
  1704.     gDoingBatchODOCs = false;
  1705. } // BatchProcessOneFile
  1706.  
  1707.  
  1708.  
  1709. // ---------------------------------------------------------------------
  1710. // Handle choosing items from the Apple menu
  1711. static void DoAppleMenu(short theItem)
  1712. {
  1713.     Str255        name;
  1714.  
  1715.     if (theItem == apmn_about)
  1716.         DoAboutBox();
  1717.     else
  1718.     {
  1719.         GetMenuItemText(myMenus[apmn_ID - menu_offset], theItem, name);
  1720.         OpenDeskAcc(name);
  1721.     }
  1722. } // DoAppleMenu
  1723.  
  1724.  
  1725. // ---------------------------------------------------------------------
  1726. // Handle choosing items from the File menu
  1727. static void DoFileMenu(short theItem)
  1728. {
  1729.     WindowPtr    theFrontWindow;
  1730.  
  1731.     theFrontWindow = FrontWindow();
  1732.     switch (theItem)
  1733.     {
  1734.         case fmn_new:                                /* New File */
  1735.                 DoFile_New();
  1736.                 break;
  1737.  
  1738.         case fmn_open:                                 /* Open a file */
  1739.                 DoFile_Open();
  1740.                 break;
  1741.  
  1742.         case fmn_close:                                /* Close */
  1743.                 if (theFrontWindow == gImageWindowPtr)
  1744.                     CloseImageWindow();
  1745.                 else if (theFrontWindow == gSrcWind_Window)
  1746.                     DoFile(fmn_close);
  1747.                 break;
  1748.  
  1749.         case fmn_save:                            /* Save */
  1750.                 if (theFrontWindow == gSrcWind_Window)
  1751.                 {    
  1752.                     DoFile(fmn_save);
  1753.                 }                        
  1754.                 else if (theFrontWindow == gImageWindowPtr)
  1755.                         SaveOutputFile(false, gtheSCComponent); // don't prompt for name
  1756.                 else if (theFrontWindow == (WindowPtr)gp2wWindow)
  1757.                     Save_StatusWindow();
  1758.                 break;
  1759.  
  1760.         case fmn_saveas:                            /* Save as… */
  1761.                 if (theFrontWindow == gSrcWind_Window)
  1762.                 {    
  1763.                     DoFile(fmn_saveas);
  1764.                 }
  1765.                 else if (theFrontWindow == gImageWindowPtr)
  1766.                     SaveOutputFile(true, gtheSCComponent); // prompt for name
  1767.                 else if (theFrontWindow == (WindowPtr)gp2wWindow)
  1768.                     Save_StatusWindow();
  1769.                 break;
  1770.  
  1771.         case fmn_revert:                            /* Revert to saved */
  1772.                 if (theFrontWindow == gSrcWind_Window)
  1773.                 {    
  1774.                     DoFile(fmn_revert);
  1775.                 }                        
  1776.                 break;
  1777.  
  1778.         case fmn_quit:
  1779.                 ask_about_quit();
  1780.                 // if user still wanted to quit, try to close editor file
  1781.                 if (AppIsQuitting())
  1782.                     if (DoFile(fmn_close))
  1783.                         ;
  1784.                 break;    /* Quit the program */
  1785.     }
  1786. } // DoFileMenu
  1787.  
  1788.  
  1789.  
  1790. // ---------------------------------------------------------------------
  1791. // Handle choosing items from the Edit menu
  1792. static void DoEditMenu(short theItem)
  1793. {
  1794.     WindowPtr    theFrontWindow;
  1795.  
  1796.     theFrontWindow = FrontWindow();
  1797.  
  1798.     if (SystemEdit(theItem-1) != 0)
  1799.         return;
  1800.  
  1801.     /* handle the menu items for the front window */
  1802.         switch (theItem)
  1803.         {
  1804.             case edmn_undo:                    /*undo*/
  1805.                 if (theFrontWindow == gSrcWind_Window)
  1806.                 {
  1807.                     SrcWindUndo();
  1808.                 }
  1809.                 else if (theFrontWindow == gImageWindowPtr)
  1810.                 {
  1811.                 }
  1812.                 break;
  1813.  
  1814.             case edmn_redo:                    /*redo*/
  1815.                 if (theFrontWindow == gSrcWind_Window)
  1816.                 {
  1817.                     SrcWindRedo();
  1818.                 }
  1819.                 else if (theFrontWindow == gImageWindowPtr)
  1820.                 {
  1821.                 }
  1822.                 break;
  1823.  
  1824.             case edmn_cut:
  1825.                 if (theFrontWindow == gSrcWind_Window)
  1826.                 {
  1827.                     SrcWindCutSelToClipboard();
  1828.                     gSrcWind_dirty = 1;
  1829.                 }
  1830.                 break;
  1831.  
  1832.             case edmn_copy:                    /*copy*/
  1833.                 if (theFrontWindow == gSrcWind_Window)
  1834.                 {
  1835.                     SrcWindCopySelToClipboard();
  1836.                 }
  1837.                 else if (theFrontWindow == gImageWindowPtr)
  1838.                 {
  1839.                     ZeroScrap(); // clear out the clipboard
  1840.                     paint_to_picture(false);
  1841.                     TEToScrap(); // export
  1842.                 }
  1843.                 else if (theFrontWindow == (WindowPtr)gp2wWindow)
  1844.                 {
  1845.                     ZeroScrap(); // clear out the clipboard
  1846.                     TECopy(gp2wWindow->p2wTEHandle);
  1847.                     TEToScrap(); // export
  1848.                 }
  1849.                 break;
  1850.     
  1851.             case edmn_paste:
  1852.                 if (theFrontWindow == gSrcWind_Window)
  1853.                 {
  1854.                     SrcWindPasteFromClipboard();
  1855.                     gSrcWind_dirty = 1;
  1856.                 }
  1857.                 break;
  1858.  
  1859.             case edmn_clear:
  1860.                 if (theFrontWindow == gSrcWind_Window)
  1861.                 {
  1862.                     SrcWindClearSel();
  1863.                     gSrcWind_dirty = 1;
  1864.                 }
  1865.                 break;
  1866.  
  1867.             case edmn_selectAll:
  1868.                 if (theFrontWindow == gSrcWind_Window)
  1869.                 {
  1870.                     SelectAllText();
  1871.                 }
  1872.                 else if (theFrontWindow == (WindowPtr)gp2wWindow)
  1873.                 {
  1874.                     p2w_SelectAll(gp2wWindow);
  1875.                 }
  1876.                 break;
  1877.  
  1878.             case edmn_goto:
  1879.                 choose_goto_line();
  1880.                 break;
  1881.  
  1882.             case edmn_matchbrace:
  1883.                 MatchBracesAtCurSel();
  1884.                 break;
  1885.         } /*switch*/
  1886. } // DoEditMenu
  1887.  
  1888.  
  1889.  
  1890. // ---------------------------------------------------------------------
  1891. // Handle choosing items from the Template menu
  1892. static void DoTemplateMenu(short theMenu, short theItem)
  1893. {
  1894.     switch(theItem)
  1895.     {
  1896.         case temn_import:
  1897.             ImportTemplates();
  1898.             break;
  1899.         default:
  1900.             HandleTemplateMenu(theMenu, theItem);
  1901.             break;
  1902.     }
  1903. } // DoTemplateMenu
  1904.  
  1905.  
  1906. // ---------------------------------------------------------------------
  1907. // Handle choosing items from the Image menu
  1908. static void DoImageMenu(short theItem)
  1909. {
  1910.     if (theItem == immn_dither)
  1911.     {
  1912.         // toggle it
  1913.         (**gPrefs2Use_h).doDither = !(**gFilePrefs_h).doDither;
  1914.         // make sure file prefs are updated too (in case using app prefs)
  1915.         (**gFilePrefs_h).doDither = (**gPrefs2Use_h).doDither;
  1916.         InvalRect_ImageWindow(false);
  1917.     }
  1918. } // DoImageMenu
  1919.  
  1920.  
  1921. // ---------------------------------------------------------------------
  1922. // Handle choosing items from the View menu
  1923. static void DoViewMenu(short theItem)
  1924. {
  1925.     // Set the file prefs
  1926.     (**gPrefs2Use_h).imageMagFactor = theItem;
  1927.     SetImageWindowMag(theItem);
  1928. } // DoViewMenu
  1929.  
  1930.  
  1931. // ---------------------------------------------------------------------
  1932. // Handle choosing items from the Image menu
  1933. static void DoPaletteMenu(short theItem)
  1934. {
  1935.     switch(theItem)
  1936.     {
  1937.         case palette_none:
  1938.             gUsingCustomPalette = false;
  1939.             gColorQuantMethod = -1;
  1940.             break;
  1941.  
  1942.         case palette_default:
  1943.             gUsingCustomPalette = true;
  1944.             gColorQuantMethod = systemMethod;
  1945.             break;
  1946.  
  1947.         case palette_median:
  1948.             gUsingCustomPalette = true;
  1949.             gColorQuantMethod = medianMethod;
  1950.             break;
  1951.  
  1952.         case palette_popular:
  1953.             gUsingCustomPalette = true;
  1954.             gColorQuantMethod = popularMethod;
  1955.             break;
  1956.  
  1957.         case palette_var_min:
  1958.             gUsingCustomPalette = true;
  1959.             gColorQuantMethod = varianceMethod;
  1960.             break;
  1961.  
  1962.         case palette_octree:
  1963.             gUsingCustomPalette = true;
  1964.             gColorQuantMethod = octreeMethod;
  1965.             break;
  1966.     }
  1967.  
  1968.     if (((WindowPeek)gImageWindowPtr)->visible)
  1969.         SetCustomPalette(!gInBackground);
  1970. } // DoPaletteMenu
  1971.  
  1972.  
  1973.  
  1974. // ---------------------------------------------------------------------
  1975. // Handle choosing items from the Image menu
  1976. static void DoPrefsMenu(short theItem)
  1977. {
  1978.     switch(theItem)
  1979.     {
  1980.         case pref_app:
  1981.             DisableMenus();
  1982.             AppPrefs_Prompt_Init(); // mmodal
  1983.             break;
  1984.  
  1985.         case pref_file:
  1986.             if (gSrcWind_dirty)
  1987.                 if (DoFile(fmn_save)) ;
  1988.             DisableMenus(); // re-enabled when ok/cancel pressed
  1989.             FilePrefs_Prompt_Init(gSrcWind_VRefNum, gSrcWind_FileName); // mmodal
  1990.             break;
  1991.     }
  1992. } // DoPrefsMenu
  1993.  
  1994.  
  1995. // ---------------------------------------------------------------------
  1996. // Handle choosing items from the Render menu
  1997. static void DoRenderMenu(short theItem)
  1998. {
  1999.     switch(theItem)
  2000.     {
  2001.         case rnmn_render:                            /* Render */
  2002.                 if (gSrcWind_dirty)
  2003.                     if (DoFile(fmn_save))
  2004.                         ;
  2005.                 gBeginRendering = true;
  2006.                 break;
  2007.  
  2008.         case rnmn_pause:                            /* pause trace */
  2009.                 pause_it();
  2010.                 break;    
  2011.  
  2012.         case rnmn_stop:                                /* Abort trace in progress? */
  2013.                 ask_about_stop();
  2014.                 break;        
  2015.     }
  2016. } // DoRenderMenu
  2017.  
  2018.  
  2019. // ---------------------------------------------------------------------
  2020. // Handle choosing items from the Processing menu
  2021. #ifdef XXX
  2022. static void DoPPMenu(short theItem)
  2023. {
  2024.     switch (theItem)
  2025.     {
  2026.         case psmn_border:
  2027.             draw_border();
  2028.             break;
  2029.  
  2030.         case psmn_darken:
  2031.             darken_image();
  2032.             break;
  2033.  
  2034.         case psmn_lighten:
  2035.             lighten_image();
  2036.             break;
  2037.  
  2038.         case psmn_reduceC:
  2039.             reduce_contrast();
  2040.             break;
  2041.  
  2042.         case psmn_increaseC:
  2043.             increase_contrast();
  2044.             break;
  2045.  
  2046.         case psmn_invert:
  2047.             invert_image();
  2048.             break;
  2049.  
  2050.         case psmn_revert:
  2051.             revert_image();
  2052.             break;
  2053.     }
  2054. } // DoPPMenu
  2055. #endif
  2056.  
  2057.  
  2058. // ---------------------------------------------------------------------
  2059. // Handle choosing items from the Windows menu
  2060. static void DoWindMenu(short theItem)
  2061. {
  2062.     switch (theItem)
  2063.     {
  2064.         case wndmn_status:
  2065.             if (gp2wWindow)
  2066.                 {
  2067.                 SelectWindow((WindowPtr)gp2wWindow);
  2068.                 }
  2069.             break;
  2070.  
  2071.         case wndmn_source:
  2072.             if ((gSrcWind_Window) && (gSrcWind_visible))
  2073.                 {
  2074.                 SelectWindow(gSrcWind_Window);
  2075.                 }
  2076.             break;
  2077.  
  2078.         case wndmn_image:
  2079.             if (((WindowPeek)gImageWindowPtr)->visible)
  2080.                 {
  2081.                 SelectWindow(gImageWindowPtr);
  2082.                 }
  2083.             break;
  2084.  
  2085.         case wndmn_autoscroll:
  2086.             if (gp2wWindow)
  2087.                 {
  2088.                 // flip its state
  2089.                 p2w_AlwaysScrollToBottom(gp2wWindow, !p2w_AlwaysScrollToBottomState(gp2wWindow));
  2090.                 // if we are now auto-scrolling, force it to the bottom immediately
  2091.                 if (p2w_AlwaysScrollToBottomState(gp2wWindow))
  2092.                     p2w_ScrollEnd(gp2wWindow);
  2093.                 }
  2094.             break;
  2095.     }
  2096. } // DoWindMenu
  2097.  
  2098.  
  2099. // ---------------------------------------------------------------------
  2100. // Handle choosing items from various menus
  2101. static void DoMenuCommand(long m)
  2102. {
  2103.     short        theMenu, theItem;
  2104.  
  2105.     theMenu = (m >> 16);
  2106.     theItem = m;
  2107.     switch (theMenu)
  2108.     {
  2109.         case apmn_ID:                /* Apple Menu */
  2110.             DoAppleMenu(theItem);
  2111.             break;
  2112.             
  2113.         case fmn_ID:                /* File Menu */
  2114.             DoFileMenu(theItem);
  2115.             break;
  2116.  
  2117.         case edmn_ID:                /* Edit Menu */
  2118.             DoEditMenu(theItem);
  2119.             break;
  2120.  
  2121.         case temn_ID:                /* Template Menu */
  2122.             DoTemplateMenu(theMenu, theItem);
  2123.             break;
  2124.  
  2125.         case immn_ID:                /* Image Menu */
  2126.             DoImageMenu(theItem);
  2127.             break;
  2128.  
  2129.         case viewmn_ID:                /* View submenu */
  2130.             DoViewMenu(theItem);
  2131.             break;
  2132.  
  2133.         case plmn_ID:                /* Custom Palette submenu */
  2134.             DoPaletteMenu(theItem);
  2135.             break;
  2136.  
  2137.         case pfmn_ID:                /* Prefs submenu */
  2138.             DoPrefsMenu(theItem);
  2139.             break;
  2140.  
  2141.         case rnmn_ID:                /* Render Menu */
  2142.             DoRenderMenu(theItem);
  2143.             break;
  2144.  
  2145.         case wndmn_ID:                 /* Windows menu */
  2146.             DoWindMenu(theItem);
  2147.             break;
  2148.  
  2149.         case kHMHelpMenuID: /* Defined in Balloons.h */
  2150. // if we decide to add help in our own Help menu...
  2151.             break;
  2152.  
  2153.         default:
  2154.             // If it is none of the above, it may be one of the dynamically added
  2155.             // template menus...
  2156.             HandleTemplateMenu(theMenu, theItem);
  2157.             break;
  2158.     }
  2159.  
  2160.     HiliteMenu(0);
  2161.  
  2162. } // DoMenuCommand
  2163.  
  2164.  
  2165.  
  2166. // ---------------------------------------------------------------------
  2167. // Set all menu items availability depending on application states
  2168. static void AdjustMenus(void)
  2169. {
  2170.     short        i;
  2171.     Boolean        inLowMemMode;
  2172.     WindowPtr    theFrontWindow;
  2173.  
  2174.     // Find out which window is in front, many menus depend on which is frontmost.
  2175.     theFrontWindow    = FrontWindow();
  2176.     inLowMemMode    =  InLowMemoryMode();
  2177.  
  2178. #ifdef DO_BETA
  2179.     // if we timed out, pretend we're rendering...
  2180.     // this will force the important menus OFF so they cannot be accessed.
  2181.     // this tricky way of doing things is simply to slow down MacNosy's out there...
  2182.     if (gTimeoutFlag > 0.0)
  2183.         gDoingRender = (gTimeoutFlag > 0.0);
  2184. #endif // DO_BETA
  2185.  
  2186.     //======== APPLE
  2187.  
  2188.     SetItemEnable(myMenus[apmn_ID - menu_offset], apmn_about,  !inLowMemMode && !gDoingRender); /* about box */
  2189.  
  2190.  
  2191.     //======== FILE
  2192.  
  2193.     // disable whole menu if dialog is up
  2194.     SetItemEnable(myMenus[fmn_ID - menu_offset], 0, !IsMModalDialogDisplayed());
  2195.  
  2196.     // ---- New
  2197.     SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_new, !gDoingRender && !gSrcWind_dirty && !inLowMemMode);
  2198.  
  2199.     // ---- Open
  2200.     SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_open, !gDoingRender && !gSrcWind_dirty && !inLowMemMode);
  2201.  
  2202.     // ---- Close
  2203.     SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_close, false);
  2204.     if (theFrontWindow == gSrcWind_Window)
  2205.     {
  2206.         if (!gDoingRender)
  2207.             SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_close, true);
  2208.         }
  2209. /* -- not yet, need to prompt to save first
  2210.     else if (theFrontWindow == gImageWindowPtr)
  2211.     {
  2212.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_close, true);
  2213.     }
  2214. */
  2215.  
  2216.     // ---- Save
  2217.     if (theFrontWindow == gSrcWind_Window)
  2218.     {
  2219.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_save, gSrcWind_dirty || (gSrcWind_VRefNum == 0));
  2220.     }
  2221.     else if (theFrontWindow == (WindowPtr)gp2wWindow)
  2222.     {
  2223.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_save, true);
  2224.     }
  2225.     else if (theFrontWindow == gImageWindowPtr)
  2226.     {
  2227.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_save, !gDoingRender && gImageWindIsValid);
  2228.     }
  2229.  
  2230.     // ---- Save As
  2231.     if (theFrontWindow == gSrcWind_Window)
  2232.     {
  2233.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_saveas, true);
  2234.     }
  2235.     else if (theFrontWindow == gImageWindowPtr)
  2236.     {
  2237.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_saveas, !gDoingRender && gImageWindIsValid);
  2238.     }
  2239.     else
  2240.     {
  2241.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_saveas, false);
  2242.     }
  2243.  
  2244.     // ---- Revert
  2245.     if (theFrontWindow == gSrcWind_Window)
  2246.     {
  2247.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_revert, !gDoingRender && gSrcWind_dirty && (gSrcWind_VRefNum != 0));
  2248.     }
  2249.     else if (theFrontWindow == gImageWindowPtr)
  2250.     {
  2251.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_revert, FALSE);
  2252.     }
  2253.     else
  2254.     {
  2255.         SetItemEnable(myMenus[fmn_ID - menu_offset], fmn_revert, FALSE);
  2256.     }
  2257.  
  2258.  
  2259.  
  2260.     //======== EDIT
  2261.  
  2262.     // ---- undo
  2263.     if (theFrontWindow == gSrcWind_Window)
  2264.     {
  2265.         gCanUndo = CheckSrcWindCanUndo();
  2266.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_undo, gCanUndo);
  2267.     }
  2268.     else
  2269.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_undo, false);
  2270.  
  2271.     // ---- cut
  2272.     if (theFrontWindow == gSrcWind_Window)
  2273.     {
  2274.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_cut,
  2275.                 GetSrcWindselStart() != GetSrcWindselEnd());
  2276.     }
  2277.     else
  2278.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_cut, false);
  2279.  
  2280.     // ---- copy
  2281.     if (theFrontWindow == gSrcWind_Window)
  2282.     {
  2283.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_copy,
  2284.                 GetSrcWindselStart() != GetSrcWindselEnd());
  2285.     }
  2286.     else
  2287.     if (theFrontWindow == gImageWindowPtr)
  2288.     {
  2289.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_copy, !gDoingRender && gImageWindIsValid);
  2290.     }
  2291.     else
  2292.     if (theFrontWindow == (WindowPtr)gp2wWindow)
  2293.     {
  2294.         SetItemEnable(myMenus[edmn_ID - menu_offset],
  2295.             edmn_copy,
  2296.             (**gp2wWindow->p2wTEHandle).selStart != (**gp2wWindow->p2wTEHandle).selEnd);
  2297.     }
  2298.  
  2299.     // ---- paste
  2300.     if (theFrontWindow == gSrcWind_Window)
  2301.     { // can only paste into src window
  2302.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_paste, true);
  2303.     }
  2304.     else
  2305.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_paste, false);
  2306.  
  2307.     // ---- clear
  2308.     if (theFrontWindow == gSrcWind_Window)
  2309.     {
  2310.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_clear,
  2311.                 GetSrcWindselStart() != GetSrcWindselEnd());
  2312.     }
  2313.     else
  2314.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_clear, false);
  2315.  
  2316.  
  2317.     // ---- select all
  2318.     if ((theFrontWindow == gSrcWind_Window) || (theFrontWindow == (WindowPtr)gp2wWindow))
  2319.     {
  2320.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_selectAll, true);
  2321.     }
  2322.     else
  2323.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_selectAll, false);
  2324.  
  2325.     // ---- redo
  2326.     if (theFrontWindow == gSrcWind_Window)
  2327.     {
  2328.         gCanRedo = CheckSrcWindCanRedo();
  2329.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_redo, gCanRedo);
  2330.     }
  2331.     else
  2332.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_redo, false);
  2333.  
  2334.     // ---- goto
  2335.     SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_goto, gSrcWind_visible);
  2336.  
  2337.     // ---- match braces
  2338.     if (theFrontWindow == gSrcWind_Window)
  2339.     {
  2340.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_matchbrace, true);
  2341.     }
  2342.     else
  2343.         SetItemEnable(myMenus[edmn_ID - menu_offset], edmn_matchbrace, false);
  2344.  
  2345.  
  2346.  
  2347.     //======== TEMPLATE
  2348.  
  2349.     // disable whole menu if dialog is up
  2350.     SetItemEnable(myMenus[temn_ID - menu_offset], 0, !IsMModalDialogDisplayed());
  2351.  
  2352.     // ---- import file
  2353.     SetItemEnable(myMenus[temn_ID - menu_offset], temn_import, !TemplatesImported() && !inLowMemMode); // false when already read
  2354.  
  2355.  
  2356.     //======== IMAGE
  2357.  
  2358.     // disable whole menu if dialog is up
  2359.     SetItemEnable(myMenus[immn_ID - menu_offset], 0, !IsMModalDialogDisplayed());
  2360.  
  2361.     // ---- view
  2362.     SetItemEnable(myMenus[immn_ID - menu_offset], immn_view, true);
  2363.         // should disable view submenu if !gSrcWind_visible...
  2364.  
  2365.     // ---- dither
  2366.     SetItemEnable(myMenus[immn_ID - menu_offset], immn_dither, gHas32BitQD);
  2367.     CheckItem(myMenus[immn_ID - menu_offset], immn_dither, ((**gPrefs2Use_h).doDither && gHas32BitQD));
  2368.  
  2369.     // ---- custom palette
  2370.     SetItemEnable(myMenus[immn_ID - menu_offset], immn_custom, true);
  2371.  
  2372.  
  2373.     //======== RENDER
  2374.  
  2375.     // disable whole menu if dialog is up
  2376.     SetItemEnable(myMenus[rnmn_ID - menu_offset], 0, !IsMModalDialogDisplayed());
  2377.  
  2378.     // ---- render
  2379.     SetItemEnable(myMenus[rnmn_ID - menu_offset], rnmn_render,
  2380.                 !gDoingRender && (gSrcWind_VRefNum != 0) && !inLowMemMode);
  2381.  
  2382.     // ---- pause rendering
  2383.     SetItemEnable(myMenus[rnmn_ID - menu_offset], rnmn_pause, gDoingRender);
  2384.  
  2385.     // ---- stop rendering
  2386.     SetItemEnable(myMenus[rnmn_ID - menu_offset], rnmn_stop, gDoingRender);
  2387.  
  2388.     //======== WINDOWS
  2389.  
  2390.     // disable whole menu if dialog is up
  2391.     SetItemEnable(myMenus[wndmn_ID - menu_offset], 0, !IsMModalDialogDisplayed());
  2392.  
  2393.     // ---- [1] status window
  2394.     CheckItem(myMenus[wndmn_ID - menu_offset], wndmn_status, theFrontWindow == (WindowPtr)gp2wWindow);
  2395.     SetItemEnable(myMenus[wndmn_ID - menu_offset], wndmn_status, gp2wWindow != NULL);
  2396.  
  2397.     // ---- [2] source window
  2398.     CheckItem(myMenus[wndmn_ID - menu_offset], wndmn_source, theFrontWindow == gSrcWind_Window);
  2399.     SetItemEnable(myMenus[wndmn_ID - menu_offset], wndmn_source, gSrcWind_visible);
  2400.  
  2401.     // ---- [3] image window
  2402.     CheckItem(myMenus[wndmn_ID - menu_offset], wndmn_image, theFrontWindow == gImageWindowPtr);
  2403.     SetItemEnable(myMenus[wndmn_ID - menu_offset], wndmn_image, gImageWindowPtr && ((WindowPeek)gImageWindowPtr)->visible);
  2404.  
  2405.     // ---- [4] Auto-scroll the status window
  2406.     CheckItem(myMenus[wndmn_ID - menu_offset], wndmn_autoscroll, p2w_AlwaysScrollToBottomState(gp2wWindow));
  2407.     SetItemEnable(myMenus[wndmn_ID - menu_offset], wndmn_autoscroll, gp2wWindow != NULL);
  2408.  
  2409.     //======== VIEW SUBMENU
  2410.  
  2411.     SetItemEnable(mySubMenus[viewmn_ID - submenu_offset], 0, true);
  2412.     for (i=viewmn_hidden; i <= viewmn_x4; i++)
  2413.         CheckItem(mySubMenus[viewmn_ID - submenu_offset], i, i == (**gPrefs2Use_h).imageMagFactor);
  2414.  
  2415.  
  2416.     //======== CUSTOM PALETTE SUBMENU
  2417.  
  2418.     for (i=palette_none; i <= palette_popular; i++)
  2419.         SetItemEnable(mySubMenus[plmn_ID - submenu_offset], i,
  2420.                 gHasPictUtils && (i!=2) && (theFrontWindow == gImageWindowPtr) );
  2421.     CheckItem(mySubMenus[plmn_ID - submenu_offset], palette_none, !gUsingCustomPalette);
  2422.     CheckItem(mySubMenus[plmn_ID - submenu_offset], palette_default, gColorQuantMethod == systemMethod);
  2423.     CheckItem(mySubMenus[plmn_ID - submenu_offset], palette_median, gColorQuantMethod == medianMethod);
  2424.     CheckItem(mySubMenus[plmn_ID - submenu_offset], palette_popular, gColorQuantMethod == popularMethod);
  2425.  
  2426.     //======== File Prefs SUBMENU
  2427.  
  2428.     SetItemEnable(mySubMenus[pfmn_ID - submenu_offset], pref_file,
  2429.                 !gDoingRender /* && (gSrcWind_VRefNum != 0) */ );
  2430.  
  2431. } // AdjustMenus
  2432.  
  2433.  
  2434.  
  2435. // ---------------------------------------------------------------------
  2436. // Handle mouse down in windows or menus
  2437. static void DoMouseDown(void)
  2438. {
  2439.     short            code;
  2440.     WindowPtr        whichWindow;
  2441.     Rect            theWindowPos;    
  2442.  
  2443.     code = FindWindow(gTheEvent.where, &whichWindow);
  2444.  
  2445.     // don't allow window switch events
  2446.     if (whichWindow != FrontWindow() &&
  2447.         (code != inSysWindow) && (code != inMenuBar))
  2448.         {
  2449.         // if a dialog is up and we clicked outside it... beep & do nothing!
  2450.         if (IsMModalDialogDisplayed() && (whichWindow != GetCurrMModalDialog()))
  2451.             {
  2452.             SysBeep(4);
  2453.             return;
  2454.             }
  2455.         }
  2456.  
  2457.     if (whichWindow == gSrcWind_Window)
  2458.         {
  2459.         DoEditMouseDown (code, whichWindow, &gTheEvent);
  2460.         }
  2461.     else
  2462.     {
  2463.         switch (code)
  2464.         {
  2465.             case inMenuBar:
  2466.                 ShowArrowCursor();
  2467.                 AdjustMenus();
  2468.                 DoMenuCommand(MenuSelect(gTheEvent.where));
  2469.                 break;
  2470.  
  2471.             case inSysWindow:
  2472.                 SystemClick(&gTheEvent, whichWindow);
  2473.                 break;
  2474.  
  2475.             case inGoAway:
  2476.                 // neither Image nor Status have a close box, and the
  2477.                 // Source window's close is handled in DoEditMouseDown()
  2478.                 if (TrackGoAway(whichWindow, gTheEvent.where))
  2479.                     ;
  2480.                 break;
  2481.  
  2482.             case inGrow:
  2483.                 if ((whichWindow == (WindowPtr)gp2wWindow) && (gp2wWindow))
  2484.                 { // Status Window
  2485.                     p2w_DoGrow(gp2wWindow, &gTheEvent);
  2486.                     GetGlobalWindowRect((WindowPtr)gp2wWindow, &theWindowPos);
  2487.                     (**gFilePrefs_h).statWind_pos = theWindowPos;
  2488.                     // also remember this as default for next time
  2489.                     (**gDefltFilePrefs_h).statWind_pos = theWindowPos;
  2490.                 }
  2491.                 else if ((whichWindow == gImageWindowPtr) && (gImageWindowPtr))
  2492.                 { // Image Window
  2493.                     DoGrowImageWindow(gImageWindowPtr, gTheEvent.where);
  2494.                     GetGlobalWindowRect(gImageWindowPtr, &theWindowPos);
  2495.                     (**gFilePrefs_h).imageWind_pos = theWindowPos;
  2496. // Uncomment the next line to keep updating the default
  2497. // image wind position, not a good idea, IMHO.
  2498. /*
  2499.                     // also remember this as default for next time
  2500.                     (**gDefltFilePrefs_h).imageWind_pos = theWindowPos;
  2501. */
  2502.                 }
  2503.                 break;
  2504.  
  2505.             case inZoomIn:
  2506.             case inZoomOut:
  2507.                 SelectWindow(whichWindow);
  2508.                 if (TrackBox(whichWindow, gTheEvent.where, code))
  2509.                 {
  2510.                     if ((whichWindow == (WindowPtr)gp2wWindow) && (gp2wWindow))
  2511.                         p2w_DoZoom(gp2wWindow, code);
  2512.                     else if ((whichWindow == gImageWindowPtr) && (gImageWindowPtr))
  2513.                         ; // none
  2514.                 }
  2515.                 break;
  2516.  
  2517.             case inDrag:
  2518.                 if (whichWindow != FrontWindow())
  2519.                     SelectWindow(whichWindow);
  2520.                 else
  2521.                 {
  2522.                     DragWindow(whichWindow, gTheEvent.where, &gDragBounds);
  2523.                     GetGlobalWindowRect(whichWindow, &theWindowPos);
  2524.                     if ((whichWindow == (WindowPtr)gp2wWindow) && (gp2wWindow))
  2525.                     { // Status window
  2526.                         (**gFilePrefs_h).statWind_pos = theWindowPos;
  2527.                         // also remember this as default for next time
  2528.                         (**gDefltFilePrefs_h).statWind_pos = theWindowPos;
  2529.                     }
  2530.                     else if ((whichWindow == gImageWindowPtr) && (gImageWindowPtr))
  2531.                     { // Image Window
  2532.                         (**gFilePrefs_h).imageWind_pos = theWindowPos;
  2533.     // Uncomment the next line to keep updating the default
  2534.     // image wind position, not a good idea, IMHO.
  2535.     /*
  2536.                         // also remember this as default for next time
  2537.                         (**gDefltFilePrefs_h).imageWind_pos = theWindowPos;
  2538.     */
  2539.                     }
  2540.                 }
  2541.                 break;
  2542.  
  2543.             case inContent:
  2544.                 if (whichWindow != FrontWindow())
  2545.                     SelectWindow(whichWindow);
  2546.                 else
  2547.                 {
  2548.                     if ((whichWindow == (WindowPtr)gp2wWindow) && (gp2wWindow))
  2549.                         p2w_DoContentClick(gp2wWindow, &gTheEvent);
  2550.                     else if (whichWindow == gImageWindowPtr)
  2551.                     {
  2552.                         SetPort(whichWindow);
  2553.                         GlobalToLocal(&gTheEvent.where);
  2554.                         // perform marquee dragging in here!
  2555.                     }
  2556.                 }
  2557.                 break;
  2558.         }
  2559.     }
  2560. } // DoMouseDown
  2561.  
  2562.  
  2563.  
  2564. // ---------------------------------------------------------------------
  2565. // Handle key downs
  2566. static void DoKeyDown(void)
  2567. {
  2568.     char    theChar, theVirtualCode;
  2569.  
  2570.     theChar = gTheEvent.message & charCodeMask;
  2571.     theVirtualCode = (gTheEvent.message & keyCodeMask) >> 8;
  2572.  
  2573.     if (gTheEvent.modifiers & cmdKey)
  2574.     {
  2575.         AdjustMenus();
  2576.         DoMenuCommand(MenuKey(theChar));
  2577.     }
  2578.     else
  2579.     {
  2580.         // Handle Status window
  2581.         if (FrontWindow() == (WindowPtr)gp2wWindow)
  2582.             p2w_DoKeyDown(gp2wWindow, theVirtualCode);
  2583.         // Handle Editor window
  2584.         else if (FrontWindow() == gSrcWind_Window)
  2585.         {
  2586.             switch (theVirtualCode)
  2587.             {
  2588.                 case 0x33:                // delete
  2589.                     if (GetSrcWindselStart() != GetSrcWindselEnd())
  2590.                     {
  2591.                         SrcWindClearSel();    // delete selection
  2592.                         gSrcWind_dirty = 1;
  2593.                     }
  2594.                     else
  2595.                     {   // if there is a left char!
  2596.                         if(GetSrcWindselStart() > 0)
  2597.                         {
  2598.                             SrcWindTEDeleteLeftCharKey(); // delete char
  2599.                             gSrcWind_dirty = 1;
  2600.                         }
  2601.                     }
  2602.                     break;
  2603.  
  2604.                 case 0x73:                // HOME
  2605.                     ScrollEditHome();
  2606.                     break;
  2607.  
  2608.                 case 0x77:                // END
  2609.                     ScrollEditEnd();
  2610.                     break;
  2611.  
  2612.                 case 0x74:                // PAGE UP
  2613.                     ScrollEditPage(kControlPageUpPart);
  2614.                     break;
  2615.  
  2616.                 case 0x79:                // PAGE DOWN
  2617.                     ScrollEditPage(kControlPageDownPart);
  2618.                     break;
  2619.  
  2620.                 case 0x7A:                // UNDO (F1)
  2621.                     SrcWindUndo();
  2622.                     break;
  2623.  
  2624.                 case 0x78:                // CUT (F2)
  2625.                     SrcWindCutSelToClipboard();
  2626.                     gSrcWind_dirty = 1;
  2627.                     break;
  2628.  
  2629.                 case 0x63:                // COPY (F3)
  2630.                     SrcWindCopySelToClipboard();
  2631.                     break;
  2632.  
  2633.                 case 0x76:                // PASTE (F4)
  2634.                     SrcWindPasteFromClipboard();
  2635.                     gSrcWind_dirty = 1;
  2636.                     break;
  2637.                 
  2638.                 case 0x75:                // forward-del |X>
  2639.                     if (GetSrcWindselStart() != GetSrcWindselEnd())
  2640.                     {
  2641.                         SrcWindClearSel();    // delete selection
  2642.                         gSrcWind_dirty = 1;
  2643.                     }
  2644.                     else
  2645.                     {   // if there is a right char!
  2646.                         if((GetSrcWindteLength() - GetSrcWindselEnd()) > 0)
  2647.                         {
  2648.                             SrcWindTEDeleteRightCharKey(); // delete char
  2649.                             gSrcWind_dirty = 1;
  2650.                         }
  2651.                     }
  2652.                     break;
  2653.  
  2654.                 /* Cursor keys, don't dirty the buffer or require undo */
  2655.                 case 0x7B:                // <- left
  2656.                 case 0x3B:
  2657.  
  2658.                 case 0x7C:                // -> right
  2659.                 case 0x3C:
  2660.  
  2661.                 case 0x7D:                // v  down
  2662.                 case 0x3D:
  2663.  
  2664.                 case 0x7E:                // ^  up
  2665.                 case 0x3E:
  2666.                     SrcWindTEKey(theChar);
  2667.                     ShowSelect();
  2668.                     break;
  2669.  
  2670.                 default:                // all other keys
  2671.                     SrcWindTEKey(theChar);
  2672.                     gSrcWind_dirty = 1;
  2673.                     ShowSelect();
  2674.             }
  2675.         }
  2676.     }            
  2677. } // DoKeyDown
  2678.  
  2679.  
  2680.  
  2681. // ---------------------------------------------------------------------
  2682. // Handle disk inserted events (format uninit. disks if needed)
  2683. static void DoDiskEvt(EventRecord * pTheEventPtr)
  2684. {
  2685.     OSErr    anError;
  2686.     Point    aPoint;
  2687.  
  2688.     if (HiWord(pTheEventPtr->message) != noErr)
  2689.     {    // prompt to format it
  2690.         GetBestDialogPos(&aPoint, (WindowPtr)gp2wWindow);
  2691.         anError = DIBadMount(aPoint, pTheEventPtr->message);
  2692.     }
  2693. } // DoDiskEvt
  2694.  
  2695.  
  2696.  
  2697. // ---------------------------------------------------------------------
  2698. // Handle window update events
  2699. static void DoUpdateEvt(void)
  2700. {
  2701.     WindowPtr    whichWindow;
  2702.     
  2703.     whichWindow = (WindowPtr) gTheEvent.message;
  2704.     if ((whichWindow == gSrcWind_Window) && gSrcWind_Window)
  2705.         UpdateWindow (whichWindow);
  2706.     else if ((whichWindow == (WindowPtr) gp2wWindow) && gp2wWindow)
  2707.         p2w_DoUpdate(gp2wWindow);
  2708.     else if ((whichWindow == gImageWindowPtr) && gImageWindowPtr)
  2709.         UpdateImageWindow();
  2710.     else if (IsMModalDialogDisplayed())
  2711.         if (whichWindow == GetCurrMModalDialog())
  2712.         {
  2713.         BeginUpdate(whichWindow);
  2714.         DrawDialog(whichWindow);
  2715.         EndUpdate(whichWindow);
  2716.         }
  2717. } // DoUpdateEvt
  2718.  
  2719.  
  2720.  
  2721. // ---------------------------------------------------------------------
  2722. // Handle window activate events
  2723. static void DoActivateEvt(void)
  2724. {
  2725.     HandleActivate((WindowPtr) gTheEvent.message, gTheEvent.modifiers & 1);
  2726. } // DoActivateEvt
  2727.  
  2728.  
  2729.  
  2730. // ---------------------------------------------------------------------
  2731. // Handle OS Events (Suspend/resume)
  2732. static void DoOSEvt(void)
  2733. {
  2734.     switch ((gTheEvent.message & osEvtMessageMask) >> 24)  /* high byte of message */
  2735.     {
  2736.         case suspendResumeMessage:    /* suspend/resume is also an activate/deactivate */
  2737.             gInBackground = (gTheEvent.message & resumeFlag) == 0;
  2738.             HandleActivate((WindowPtr) gTheEvent.message, gInBackground);
  2739.             break;
  2740.     }
  2741.     ShowArrowCursor();
  2742.  
  2743. } // DoOSEvt
  2744.  
  2745.  
  2746.  
  2747. // ---------------------------------------------------------------------
  2748. // Handle any high level events (AppleEvents currently)
  2749. static void DoHighLevelEvt(void)
  2750. {
  2751.     DoAEvts(&gTheEvent);
  2752. } // DoHighLevelEvt
  2753.  
  2754.  
  2755. // ---------------------------------------------------------------------
  2756. // Do idle processing
  2757. static void DoIdle(void)
  2758. {
  2759.     FSSpec    aFile;
  2760.  
  2761.     // Check for timeout on startup message.  Remove the dialog after timeout.
  2762.     if (SplashScreenShown()) // if screen still up..
  2763.         UpdateSplashScreen();
  2764.  
  2765.     // Keep Editor window cursor blinking
  2766.     SrcWindMaintainCursor();
  2767.  
  2768.     // take care of next drag-n-dropped file in the queue
  2769.     if (!gDoingBatchODOCs)
  2770.         if (FileQ_NumItems() > 0)
  2771.             if (FileQ_Get(&aFile))
  2772.                 BatchProcessOneFile(&aFile);
  2773. } // DoIdle
  2774.  
  2775.  
  2776. // ---------------------------------------------------------------------
  2777. // Do everything you ever need to do in the guts of a Mac event loop
  2778. static void CheckForEvents(void)
  2779. {
  2780.     // get next event
  2781.     WaitNextEvent(everyEvent, &gTheEvent, gDoingRender?gWNEReleaseTicks:30, NULL);
  2782.  
  2783.     // handle the event
  2784.     if (IsDialogEvent(&gTheEvent) && IsMModalDialogDisplayed())
  2785.     {
  2786.         HandleMModalDialogEvent(&gTheEvent);
  2787.     }
  2788.     else
  2789.     switch (gTheEvent.what)
  2790.     {
  2791.         case mouseDown:        
  2792.                 // If the startup screen is still up, kill it
  2793.                 if (SplashScreenShown())
  2794.                     KillSplashScreen();
  2795.                 DoMouseDown();
  2796.                 break;
  2797.  
  2798.         case keyDown:
  2799.         case autoKey: 
  2800.                 // If the startup screen is still up, kill it
  2801.                 if (SplashScreenShown())
  2802.                     KillSplashScreen();
  2803.                 DoKeyDown(); 
  2804.                 break;
  2805.  
  2806.         case diskEvt:
  2807.                 DoDiskEvt(&gTheEvent);
  2808.                 break;
  2809.  
  2810.         case updateEvt:
  2811.                 DoUpdateEvt();
  2812.                 break;
  2813.  
  2814.         case activateEvt:
  2815.                 DoActivateEvt();
  2816.                 break;
  2817.  
  2818.         case osEvt:    // suspend/resume, mousemoved..
  2819.                 DoOSEvt();
  2820.                 break;
  2821.  
  2822.         case kHighLevelEvent:    // AppleEvents
  2823.                 DoHighLevelEvt();
  2824.                 break;
  2825.  
  2826.         case nullEvent:
  2827.         default:
  2828.                 break;
  2829.     }
  2830.  
  2831.     // do any idle processing
  2832.     DoIdle();
  2833.  
  2834. } // CheckForEvents
  2835.  
  2836.  
  2837. // ---------------------------------------------------------------------
  2838. // Called from rendering engine, allows Mac code to breathe while the
  2839. // renderer is parsing and rendering.  This keeps menus working..
  2840. // doImmediate if true will always breathe, otherwise it breathes every delta ticks.
  2841. // APGet_TimeSlice()    delta
  2842. // -----------------    --------
  2843. //     1                    4<<1=  8
  2844. //     2                    4<<2= 16
  2845. //     3                    4<<3= 32
  2846. //     4                    4<<4= 64
  2847. //     5                    4<<5=128
  2848. #pragma segment Main
  2849. void Cooperate(int doImmediate)
  2850. {
  2851.     int                    delta;
  2852.     volatile    long    stackCurr;    // force it to be stack-based
  2853.  
  2854.     // do a quick stack depth check
  2855.     stackCurr = gStackBase-(long)&stackCurr;    // address of stackCurr is approx. curr stack address
  2856.     if (stackCurr > gStackMax)
  2857.         gStackMax = stackCurr;
  2858.  
  2859.     // remember, this next line is: 4 shifted to the TimeSlice'th place,
  2860.     // so delta is 4*2=8,4*4=16,4*8=32, etc
  2861.     delta = 4 << APGet_TimeSlice();
  2862.     if ( doImmediate || (MAC_TICKS > gPrevTickCount + delta) )
  2863.     {
  2864.         // Update the clock before other applications
  2865.         // have breathed, so our time slices are more equally spaced
  2866.         gPrevTickCount = MAC_TICKS;
  2867.  
  2868.         // Now let other apps breathe
  2869.         CheckForEvents();
  2870.     }
  2871. } // Cooperate
  2872.  
  2873.  
  2874.  
  2875. // ------------------------------------------------------------------
  2876. // loop for events to handle until the user quits the program
  2877. #pragma segment Main
  2878.  
  2879. static void MainEventLoop(void)
  2880.     {
  2881.  
  2882. #ifdef DO_BETA
  2883.     if (gTimeoutFlag)
  2884.     {
  2885.         (void)DisplayModalDialog(rDlg_BetaTimeout, ok, 0, NULL, 0, ewcDoCentering, eMainDevice);
  2886.         SysBeep(4);
  2887.     }
  2888. #endif // DO_BETA
  2889.  
  2890.     while (!AppIsQuitting())
  2891.         {
  2892.         Cooperate(true);
  2893.         if (gBeginRendering)
  2894.             DoRendering();
  2895.         }
  2896.     } // MainEventLoop()
  2897.  
  2898.  
  2899. // ---------------------------------------------------------------------
  2900. // Do any necessary cleanup prior to exiting (call here to cleanly exit)
  2901. #pragma segment Main
  2902. void exit_handler(void)
  2903. {
  2904.     dispose_virtual();        /* close virtual file */
  2905.  
  2906.     KillImageWindow();
  2907.  
  2908.     KillOffscreen();
  2909.  
  2910.     FileQ_d();    // Tear down ODOC File Queue
  2911.  
  2912.     KillTemplateMenu();
  2913.  
  2914.     if (gSrcWind_VRefNum != 0)    // if there is a file open..
  2915.     {
  2916.         FilePrefs_Write(gSrcWind_VRefNum, gSrcWind_FileName);
  2917.         // if file is dirty, save it automatically!
  2918.         // NOTE: This would only happen if we got a QUIT appleEvent, if the user
  2919.         // picked QUIT from the menu, we would have already prompted to save.
  2920.         if (gSrcWind_dirty)
  2921.             if (DoFile(fmn_close))
  2922.                 ;
  2923.     }
  2924.  
  2925.     if (gAppPrefs_h)
  2926.         AppPrefs_Write();
  2927.  
  2928.     if (gtheSCComponent != NULL)
  2929.     {
  2930.         CloseComponent(gtheSCComponent);
  2931.         gtheSCComponent = NULL;
  2932.     }
  2933.  
  2934.     if (gp2wWindow)
  2935.     {
  2936.         p2w_DisposeWindow(gp2wWindow);
  2937.         gp2wWindow = NULL;
  2938.     }
  2939.     p2w_Terminate();
  2940.  
  2941.     SetAppQuit();    // must do this, Think C calls unexpected_exit (again) INSIDE ExitToShell!
  2942. } // exit_handler
  2943.  
  2944.  
  2945.  
  2946. // ---------------------------------------------------------------------
  2947. // Called if unexpectedly aborting
  2948. #pragma segment Main
  2949. static void unexpected_exit(void)
  2950. {
  2951.     // we are exiting within an error condition at this point...
  2952.     if (!AppIsQuitting())
  2953.     {
  2954.         if (gAppPrefs_h)
  2955.         {    
  2956.             DisposeHandle((Handle) gAppPrefs_h);
  2957.             gAppPrefs_h = NULL;    
  2958.         }    
  2959.         // fatal error, exiting
  2960.         (void)DisplayModalDialog(132, ok, 0, NULL, 0, ewcDoCentering, eMainDevice);
  2961.         exit_handler();
  2962.         ExitToShell();
  2963.     }
  2964. } // unexpected_exit
  2965.  
  2966.  
  2967.  
  2968. // ---------------------------------------------------------------------
  2969. // load all needed menus
  2970. #pragma segment Inits
  2971.  
  2972. static void SetupMenus()
  2973. {
  2974.     int        i;
  2975.     short    anError = noErr;
  2976.  
  2977.     for (i = 0; (i < num_of_menus) && !anError; i++)
  2978.     {
  2979.         myMenus[i] = GetMenu(i + menu_offset);
  2980.         if (myMenus[i] == NULL)
  2981.         {
  2982.             anError = ResError();
  2983.             (void)DisplayModalDialog(kdlog_GenericFatalErr, ok, 0, "Cannot get main menu resource", i, ewcDoCentering, eMainDevice);
  2984.             SetAppQuit();
  2985.             break;
  2986.         }
  2987.         else
  2988.         {
  2989.             if (i==0) // add DA list to Apple menu
  2990.                 AppendResMenu(myMenus[apmn_ID - menu_offset], 'DRVR');
  2991.             InsertMenu(myMenus[i], 0);
  2992.         }
  2993.     }
  2994.     for (i = 0; (i < num_of_submenus) && !anError; i++)
  2995.     {
  2996.         mySubMenus[i] = GetMenu(i + submenu_offset);
  2997.         if (mySubMenus[i] == NULL)
  2998.         {
  2999.             anError = ResError();
  3000.             (void)DisplayModalDialog(kdlog_GenericFatalErr, ok, 0, "Cannot get sub-menu resource", i, ewcDoCentering, eMainDevice);
  3001.             SetAppQuit();
  3002.             break;
  3003.         }
  3004.         else
  3005.             InsertMenu(mySubMenus[i], -1);
  3006.     }
  3007.     DrawMenuBar();
  3008.     
  3009.     // disable menus until we are ready...
  3010.     DisableMenus();
  3011.  
  3012. } // SetupMenus
  3013.  
  3014.  
  3015.  
  3016. // ------------------------------------------------------------------
  3017. #pragma segment Inits
  3018.  
  3019. static void InitAppGlobals(void)
  3020.     {
  3021.     // set up a full distribution message for display in splash screen and about box.
  3022.     gDistMessage = (StringPtr)NewPtr(256);
  3023.     strcpy((char*)gDistMessage, DISTRIBUTION_MESSAGE_1);
  3024.     strcat((char*)gDistMessage, " ");
  3025.     strcat((char*)gDistMessage, DISTRIBUTION_MESSAGE_2);
  3026.     strcat((char*)gDistMessage, " ");
  3027.     strcat((char*)gDistMessage, DISTRIBUTION_MESSAGE_3);
  3028.     c2pstr((char*)gDistMessage);
  3029.  
  3030.     /* create application prefs records */
  3031.     gAppPrefs_h = (app_prefs_hdl_t) NewHandle(sizeof(app_prefs_rec_t)); 
  3032.     MoveHHi((Handle) gAppPrefs_h);
  3033.     HLock((Handle) gAppPrefs_h);
  3034.  
  3035.     /* create default file settings record */
  3036.     gDefltFilePrefs_h = (file_prefs_hdl_t) NewHandle(sizeof(file_prefs_rec_t)); 
  3037.     MoveHHi((Handle) gDefltFilePrefs_h);
  3038.     HLock((Handle) gDefltFilePrefs_h);
  3039.  
  3040.     /* create file settings record */
  3041.     gFilePrefs_h = (file_prefs_hdl_t) NewHandle(sizeof(file_prefs_rec_t)); 
  3042.     MoveHHi((Handle) gFilePrefs_h);
  3043.     HLock((Handle) gFilePrefs_h);
  3044.  
  3045.     /* set up bounds for window dragging (multiple/big monitors) */
  3046.     SetRect(&gDragBounds, -16000, -16000, 16000, 16000);
  3047.  
  3048.     *gSrcWind_FileName = '\0';
  3049.     gRenderedOK = true;
  3050.  
  3051. #if defined(__MWERKS__)
  3052.     _ftype        = 'TEXT';    // from unix.mac.h
  3053.     _fcreator    = 'ttxt';    // from unix.mac.h
  3054. #endif
  3055.  
  3056.     }
  3057.  
  3058.  
  3059.  
  3060. // ------------------------------------------------------------------
  3061. #pragma segment Inits
  3062.  
  3063. static void InitMoreAppStuff(void)
  3064.     {
  3065.     OSErr        anError = noErr;
  3066.     PicHandle    scPicH = NULL;
  3067.     Rect        p2wRect;    
  3068.  
  3069.     //
  3070.     // Set up application globals
  3071.     //
  3072.  
  3073.     InitAppGlobals();
  3074.  
  3075.     /* Register an exit handler */
  3076.     atexit(unexpected_exit);
  3077.  
  3078.     /* Read global settings from prefs file */
  3079.     if (!AppIsQuitting())
  3080.         AppPrefs_Read();
  3081.  
  3082.     //
  3083.     // Set up splash screen (after reading prefs!)
  3084.     //
  3085.  
  3086.     if (APGet_ShowSplashScreen())
  3087.         CreateSplashScreen();
  3088.  
  3089.     //
  3090.     // Set up application menus
  3091.     //
  3092.  
  3093.     SetupMenus();
  3094.  
  3095.     //
  3096.     // Install our AEvt handler routines for accepting docs dropped on app
  3097.     //
  3098.  
  3099.     if (!AppIsQuitting())
  3100.         InstallAppleEvents();
  3101.  
  3102.     //
  3103.     // set up an empty cursor region for use by WaitNextEvent
  3104.     //
  3105.  
  3106.     if (!AppIsQuitting())
  3107.         {
  3108.         gCursorRgn = NewRgn();
  3109.         }
  3110.  
  3111.     // See if the image compression manager is installed.
  3112.     if (gHasImageCompressionMgr)
  3113.         {
  3114.         // Install and open the standard compression dialog component.
  3115.         gtheSCComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
  3116.         if (gtheSCComponent)
  3117.             {
  3118.             // Initial defaults for SC compression dialog.
  3119.             (void)SCGetInfo(gtheSCComponent, scSpatialSettingsType, &(**gDefltFilePrefs_h).sc_DialogParams);
  3120.             scPicH = GetPicture(kDemoPICTrsrcID);
  3121.             // pick a preview pict for initializing the SC defaults
  3122.             if (scPicH)
  3123.                 {
  3124.                 // set default pict
  3125.                 (void)SCDefaultPictHandleSettings(gtheSCComponent, scPicH, false);
  3126.                 // get defaults the component set up
  3127.                 (void)SCSetTestImagePictHandle(gtheSCComponent, scPicH,
  3128.                                                 NULL, scPreferScalingAndCropping);
  3129.                 }
  3130.             }
  3131.         }
  3132.  
  3133.     // Set up the status output window
  3134.     if (!anError)
  3135.         {
  3136.         anError = p2w_Init();
  3137.         if (!anError)
  3138.             {
  3139.             p2wRect = (**gDefltFilePrefs_h).statWind_pos;
  3140.             gp2wWindow = p2w_NewWindow(kWindID_p2w, &p2wRect, "\pPOV-Ray Status", true,
  3141.                                         monaco, 9, &anError);
  3142.             }
  3143.         if (anError)
  3144.             {
  3145.             (void)DisplayModalDialog(kdlog_P2W_INIT_ERROR, ok, 0, NULL, 0, ewcDoCentering, eMainDevice);
  3146.             exit_handler();
  3147.             }
  3148.         }
  3149.  
  3150.     // set up template menu
  3151.     if (!anError)
  3152.         {
  3153.         anError = InitTemplateMenu();
  3154.         if (anError)
  3155.             {
  3156.             // fatal error
  3157.             DisplayModalDialog(kdlog_GenericFatalErr, ok, 0, "Cannot create template menu",
  3158.                     anError, ewcDoCentering, eMainDevice);
  3159.             exit_handler();
  3160.             }
  3161.         }
  3162.  
  3163.     // If user wants template menu pre-built, do it
  3164.     if ((!anError) && APGet_AutoTemplates())
  3165.         ImportTemplates();
  3166.  
  3167.     if (!anError)
  3168.         InitImageWindow();
  3169.  
  3170.     if (!anError)
  3171.         SetupPalettes();
  3172.  
  3173.     SetupStdModalFilter(); /* dialogutils */
  3174.  
  3175.     // initialize the ODOC File Queue
  3176.     if (!anError)
  3177.         FileQ_c();
  3178.  
  3179.     /* Figure out how much (or little) time to give other processes (oink) */
  3180.     CalcCpuReleaseTicks(false);
  3181.  
  3182.     // for text editor
  3183.     Init_Editor();
  3184.  
  3185.     // give the user some control!
  3186.     if (!anError)
  3187.         EnableMenus();
  3188.  
  3189.     // Display initial credit screen now
  3190.     // allocate some engine buffers so that screen output works.
  3191.     pre_init_povray();
  3192.     // tell POV-Ray engine to display default (author) screen, false=no terminate
  3193.     Usage(-1, false);
  3194.     // write our own Mac-specific credits
  3195.     PrintMacCredits();
  3196.  
  3197.     // dump initial debug/system information
  3198.     DisplayConfigInfo();
  3199.  
  3200.     } // InitMoreAppStuff()
  3201.  
  3202.  
  3203.  
  3204. // ------------------------------------------------------------------
  3205. // Check one bit in the long word passed, return TRUE if bit is on.
  3206. #pragma segment Inits
  3207.  
  3208. static Boolean CheckGestaltBit(unsigned long gestaltResponse, short gestaltBit)
  3209.     {
  3210.     return( (gestaltResponse & (1<<gestaltBit) ) != 0);
  3211.     } // CheckGestaltBit
  3212.  
  3213.  
  3214.  
  3215. // ------------------------------------------------------------------
  3216. #pragma segment Inits
  3217.  
  3218. static void ValidateSystemConfig(void)
  3219.     {
  3220.     Boolean        ConfigOK    = true;
  3221.     OSErr        gestaltErr = noErr;
  3222.     long        gestaltResponse;
  3223.     char        *errStr = NULL;    
  3224. #if !defined(powerc) && !defined (__powerc)
  3225.     long        cpu68kType;
  3226. #endif
  3227.     long        sysArchitecture;
  3228.  
  3229.     //
  3230.     // Check system version stuff
  3231.     //
  3232.  
  3233.     if (errStr == NULL)
  3234.     {
  3235.         gestaltErr = Gestalt(gestaltSystemVersion, &gestaltResponse);
  3236.         if ((gestaltErr != noErr) || (gestaltResponse < 0x0700))
  3237.             errStr = "You do not have System 7.0 or newer.";    
  3238.     }
  3239.  
  3240.     //
  3241.     // Check CPU stuff
  3242.     //
  3243.  
  3244.     if (errStr == NULL)
  3245.     {
  3246.         // See if we are running on 68K or PowerPC hardware architecture
  3247.         if (Gestalt(gestaltSysArchitecture, &sysArchitecture) == noErr)
  3248.         {
  3249.     #if defined(powerc) || defined (__powerc)
  3250.             // We're compiled for PowerPC, better be one
  3251.             if (sysArchitecture != gestaltPowerPC)
  3252.                 errStr = "You do not have a recognized CPU type.";    
  3253.     #else // !PowerPC
  3254.             // what kind of 68k CPU?
  3255.             Gestalt(gestaltProcessorType, &cpu68kType);
  3256.       #if defined (NEEDS_68020)
  3257.             if (cpu68kType < gestalt68020)
  3258.                 errStr = "You do not have a 68020 or better CPU type.";    
  3259.       #endif // NEEDS_68020
  3260.             // Here we are compiled for regular 68K Mac... see if we're really
  3261.             // running on a Power Mac and issue a friendly suggestion to use
  3262.             // the native PowerMac version... allow them to continue on anyway,
  3263.             // in case they can't get the POVPPC software (and they have SoftwareFPU running.)
  3264.             if (sysArchitecture == gestaltPowerPC)
  3265.                 {
  3266.                 DisplayModalDialog(kdlog_UsePPCVersion, ok, 0, NULL, cpu68kType, ewcDoCentering, eMainDevice);
  3267.                 }
  3268.     #endif // else !PowerPC
  3269.         }
  3270.     }
  3271.  
  3272.     //
  3273.     // Check FPU stuff (only on 68k, PowerPC always has FPU)
  3274.     //
  3275.  
  3276. #if !defined(powerc) && !defined (__powerc)
  3277.     if (errStr == NULL)
  3278.     {
  3279.         if (Gestalt(gestaltFPUType, &gestaltResponse) == noErr)
  3280.         {
  3281. #if defined (NEEDS_FPU)
  3282.             // If this was compiled to REQUIRE FPU, get error if no FPU installed
  3283.             if (gestaltResponse == gestaltNoFPU)
  3284.                 errStr = "You do not have a 68881/68882 Floating Point Unit.";
  3285. #else
  3286.             // if compiled to not need FPU, give warning if running on FPU machine,
  3287.             // tell user there is a better software option (POVFPU)
  3288.             if (gestaltResponse != gestaltNoFPU)
  3289.                 DisplayModalDialog(kdlog_UseFPUVersion, ok, 0, NULL, 0, ewcDoCentering, eMainDevice);
  3290. #endif // NEEDS_FPU
  3291.         }
  3292.     }
  3293. #endif // powerc
  3294.  
  3295.     // Check Quickdraw stuff
  3296.     gHas32BitQD = false;
  3297.     gHasPictUtils = false;
  3298.     if (errStr == NULL)
  3299.     {
  3300.         if (Gestalt(gestaltQuickdrawVersion, &gestaltResponse) == noErr)
  3301.         {
  3302.             gHas32BitQD = (gestaltResponse >= gestalt32BitQD);
  3303.             gHasPictUtils = gHas32BitQD;
  3304. #if defined (NEEDS_32BITQD)
  3305.             if (!gHas32BitQD)
  3306.                 errStr = "You do not have 32 Bit Color Quickdraw.";
  3307. #endif // NEEDS_32BITQD
  3308.         }
  3309.     }
  3310.  
  3311.     // Check QuickTime version
  3312.     gHasQuickTime = false;
  3313.     gHasImageCompressionMgr = false;
  3314.     if (errStr == NULL)
  3315.     {
  3316.         if (Gestalt(gestaltQuickTime, &gestaltResponse) == noErr)
  3317.         {
  3318.             gQTVersion = gestaltResponse;
  3319.             if (gQTVersion >= 0x01608000 // at least version 1.6 final
  3320. #if defined(powerc) || defined (__powerc)
  3321.             // weak link, see if QT lib is installed
  3322.             && ((ProcPtr)SCPositionDialog != (ProcPtr)kUnresolvedCFragSymbolAddress)
  3323. #endif
  3324.             )
  3325.             {
  3326.                 gHasQuickTime = true;
  3327.                 // Check QuickTime Compression stuff
  3328.                 if (Gestalt(gestaltCompressionMgr, &gestaltResponse) == noErr)
  3329.                     gHasImageCompressionMgr = CheckGestaltBit(gestaltResponse, 4);
  3330.             }
  3331. #if defined(powerc) || defined (__powerc)
  3332. // handled with weak link check above
  3333. //            // Check PPC QuickTime lib present
  3334. //            if (Gestalt(gestaltQuickTimeFeatures, &gestaltResponse)==noErr)
  3335. //                if (!CheckGestaltBit(gestaltResponse, gestaltPPCQuickTimeLibPresent))
  3336. //                    errStr = "You do not have QuickTime PPC Shared Library installed.";
  3337. #endif
  3338.         }
  3339.     }
  3340.  
  3341.     // Check AppleEvent stuff
  3342.     gHasAppleEvents = false;
  3343.     if (errStr == NULL)
  3344.     {
  3345.         if (Gestalt(gestaltAppleEventsAttr, &gestaltResponse) == noErr)
  3346.             gHasAppleEvents = CheckGestaltBit(gestaltResponse, gestaltAppleEventsPresent);
  3347.         if (!gHasAppleEvents)
  3348.             errStr = "You do not have AppleEvents.";
  3349.     }
  3350.  
  3351.     // Show any initialization errors now
  3352.     if (errStr != NULL)    
  3353.         {    // insufficient hardware/software config..
  3354.         DisplayModalDialog(kdlog_ConfigFatalErr, ok, 0, errStr, 0, ewcDoCentering, eMainDevice);
  3355.         exit_handler();
  3356.         SetAppQuit();
  3357.         }
  3358.  
  3359.     } // ValidateSystemConfig()
  3360.  
  3361.  
  3362.  
  3363. // ------------------------------------------------------------------
  3364.  
  3365. static void ValidateAppConfig(void)
  3366.     {
  3367.  
  3368.     //
  3369.     // Is our app intact?  Check some key resources... if we are corrupt,
  3370.     // we probably don't want to bring up any (corrupt) dialogs, so again
  3371.     // we simply beep twice and exit.  This would be a great place to do a
  3372.     // checksum on our CODE #0 resource and report virus infection!
  3373.     //
  3374. /*
  3375.     if (GetNewMBar(eMenuBar) == NULL)
  3376.         {
  3377.         SysBeep(2);
  3378.         SysBeep(2);
  3379.         SetAppQuit();
  3380.         }
  3381. */
  3382.     } // ValidateAppConfig()
  3383.  
  3384.  
  3385.  
  3386. // ------------------------------------------------------------------
  3387. // Allocate more memory for stack before doing much heap stuff,
  3388. // for 68K Macs anyway.  PPC Macs have a 36 double D stack area,
  3389. // and therefore don't need any artificial enlargement.  Also, this
  3390. // System 6 style retro-tweaking is bad for Copland! [esp]
  3391.  
  3392. // No, segment 'Main' is not a bug, heap stuff must happen before any code segment loads,
  3393. // so we have to do this all in the "Main" segment.
  3394. #pragma segment Main
  3395.  
  3396. static void InitHeap(void)
  3397.     {
  3398.     volatile long        stk_size;    // force it to be a stack variable
  3399. #if !defined(powerc) && !defined (__powerc)
  3400.     app_config_hdl_t    app_config_h;
  3401.  
  3402.     app_config_h = (app_config_hdl_t)Get1Resource(kAppConfigRsrc, kAppConfigRsrcID);
  3403.     if (app_config_h)
  3404.     {
  3405.         // stackSize - # of bytes to grow the stack to (for recursion)
  3406.         // [10k < stk_size < 150k]
  3407.         stk_size = (**app_config_h).stackSize;
  3408.         if (stk_size <= 10000L)
  3409.             stk_size = 10000L;
  3410.         else if (stk_size > 150000L)
  3411.             stk_size = 150000L;
  3412.  
  3413.         // all done with this
  3414.         ReleaseResource((Handle)app_config_h);
  3415.     }
  3416.     else
  3417.     { // set to default values
  3418.         stk_size = DEFAULT_STACK_SIZE;
  3419.     }
  3420.     SetApplLimit(GetApplLimit() - stk_size);
  3421. #endif
  3422.  
  3423.     //
  3424.     // Now grow the heap out to its max extent
  3425.     //
  3426.  
  3427.     MaxApplZone();
  3428.  
  3429.     //
  3430.     // Make sure we have enough free memory to run.  Unfortunately this is
  3431.     // so early in initialization that we can't put up any dialogs (no tools),
  3432.     // instead we just beep once to let the user know something is amiss.
  3433.     //
  3434.  
  3435.     #define MIN_FREEMEM_OK        800*1024L    // for this app, 800K free is a bare minimum
  3436.     if (FreeMem() < MIN_FREEMEM_OK)
  3437.         {
  3438.         SysBeep(1);
  3439.         SetAppQuit();
  3440.         }
  3441.     else
  3442.         {
  3443.         // allocate malloc() safety buffer
  3444.         AllocateSafetyBuffer(RESERVE_MEM_SIZE);
  3445.         }
  3446.  
  3447.     //
  3448.     // Get current value of stack to compare against later
  3449.     gStackBase = (long)&stk_size;
  3450.     
  3451.     } // InitHeap()
  3452.  
  3453.  
  3454. // ------------------------------------------------------------------
  3455. // Initialize all the Macintosh toolboxes we need..
  3456. #pragma segment Inits
  3457.  
  3458. static void InitToolbox(void)
  3459.     {
  3460.     EventRecord anEvent;
  3461.     short        count;
  3462.  
  3463.     gAppRefNum = CurResFile();
  3464.  
  3465.     //
  3466.     // Init all the basic tools
  3467.     //
  3468.  
  3469.     InitGraf( (Ptr)&qd.thePort );
  3470.     InitFonts();
  3471.     InitWindows();
  3472.     InitMenus();
  3473.     TEInit();
  3474.     InitDialogs(0L);
  3475.  
  3476.     //
  3477.     // Set up the cursor, and set it initially to a watch cursor
  3478.     //
  3479.  
  3480.     InitCursor();
  3481.     InitWatchCursor();
  3482.     ShowWatchCursor();
  3483.  
  3484.     //
  3485.     // Allocate some extra master pointers to avoid mem. fragmentation
  3486.     //
  3487.  
  3488.     for (count=0; count<10; count++)
  3489.         MoreMasters();
  3490.  
  3491.     //
  3492.     // DTS Hocus Pocus to bring our app to the front
  3493.     //
  3494.  
  3495.     for (count = 1; count <= 3; count++)
  3496.         {
  3497.         EventAvail(everyEvent, &anEvent);
  3498.         // while we're here, see if option key was down on launch
  3499. //        gOptionKeyDownOnStartup = ((anEvent.modifiers & optionKey) != 0);
  3500.         }
  3501.  
  3502.     } // InitToolbox()
  3503.  
  3504.  
  3505.  
  3506. // ------------------------------------------------------------------
  3507. // One-time initialization of application-specific stuff
  3508. #pragma segment Main
  3509.  
  3510. static void InitializeApp(void)
  3511.     {
  3512. #ifdef DO_BETA
  3513.     time_t    theTime;
  3514.     time(&theTime);
  3515.     gThetmPtr = localtime(&theTime); // get todays date
  3516. #endif // DO_BETA
  3517.  
  3518.     gQuit = false;
  3519.  
  3520.     //
  3521.     // Set up application heap
  3522.     //
  3523.  
  3524.     InitHeap();
  3525.  
  3526.     //
  3527.     // Initialize Mac toolbox routines
  3528.     //
  3529.  
  3530.     if (!AppIsQuitting())
  3531.         InitToolbox();
  3532.  
  3533.     //
  3534.     // Is our application intact, or did ResEdit or Virii munge our resources?
  3535.     //
  3536.  
  3537.     if (!AppIsQuitting())
  3538.         ValidateAppConfig();
  3539.  
  3540.     //
  3541.     // Do we have the right MacOS System configuration?
  3542.     //
  3543.  
  3544.     if (!AppIsQuitting())
  3545.         ValidateSystemConfig();
  3546.  
  3547.     //
  3548.     // Do the final application initialization
  3549.     //
  3550.  
  3551.     if (!AppIsQuitting())
  3552.         InitMoreAppStuff();
  3553.     
  3554.     ShowArrowCursor();
  3555.  
  3556.     } // InitializeApp()
  3557.  
  3558.  
  3559.  
  3560. // ------------------------------------------------------------------
  3561. // Handle anything as the app quits
  3562. #pragma segment Main
  3563.  
  3564. static void TerminateApp(void)
  3565.     {
  3566.  
  3567.     //
  3568.     // close up
  3569.     //
  3570.  
  3571.     exit_handler();
  3572.  
  3573.     } // TerminateApp()
  3574.  
  3575.  
  3576.  
  3577. // ------------------------------------------------------------------
  3578. #pragma segment Main
  3579. int main(void)
  3580.     {
  3581.  
  3582. #if defined(applec)
  3583.     //
  3584.     // MPW has unpacked our initialized global area, unload their code segment
  3585.     //
  3586.     UnloadSeg((ProcPtr) _DataInit);
  3587. #endif // applec
  3588.  
  3589.     //
  3590.     // initialize application (memory, toolbox, globals)
  3591.     //
  3592.  
  3593.     InitializeApp();
  3594.  
  3595. #ifdef DO_BETA
  3596.     // If it is beyond timeout date, disable ourselves
  3597.     if (gThetmPtr->tm_year >= BETA_YEAR)
  3598.     if (gThetmPtr->tm_mon >= BETA_MONTH-1)
  3599.     if (gThetmPtr->tm_mday >= BETA_DAY)
  3600.         gTimeoutFlag = 2.10; // this will be set to 0.0 if OK to run
  3601. #endif // DO_BETA
  3602.  
  3603.  
  3604. #if defined(applec)
  3605.         UnloadSeg((ProcPtr) InitToolbox);
  3606. #endif // applec
  3607.  
  3608.     //
  3609.     // Handle user input until quit
  3610.     //
  3611.  
  3612.     if (!AppIsQuitting())
  3613.         {
  3614.         MainEventLoop();
  3615.         }
  3616.  
  3617.     //
  3618.     // Heading out, clean up
  3619.     //
  3620.  
  3621.     TerminateApp();
  3622.  
  3623.     return(0); // be nice to Mr. ANSI, he's our friend
  3624.  
  3625.     } // main()
  3626.