home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / DocShell / RlShell.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  120.6 KB  |  4,294 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        RlShell.cpp
  3.  
  4.     Contains:    Shell implementation
  5.  
  6.     Owned by:    Nick Pilch
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <39>     8/13/96    DM        1362809,1376080: reset fatal container
  13.                                     error flags to false and call handler with
  14.                                     false to disallow suppression
  15.         <38>     7/30/96    eeh        1372943: test for kTranslateItem and -108
  16.         <37>     7/28/96    DH        If there are any errors in OpenFile
  17.                                     attempting to open the draft, we will
  18.                                     immediately exit the process. Temporary
  19.                                     low-memory fix.
  20.         <36>     7/24/96    NP        1369891: Send quit event to ourselves in
  21.                                     response to the quit menu command.
  22.         <35>    19.07.1996    NP        1370120: don't call ExceptionAlert when
  23.                                     InitODSession fails. Just go away.
  24.         <34>     7/11/96    TJ        Fixed Removing of UnsavedNewDocument from
  25.                                     Stationary
  26.         <33>     7/11/96    TJ        Fixed Name of function to check for MacOS 8
  27.         <32>     6/27/96    TJ        1334727 Truning stationery into document
  28.                                     can cause it to disappeare! is now realy
  29.                                     fixed.
  30.         <31>     6/23/96    NP        1323565: Refuse to run under MacOS 8.
  31.         <30>     6/22/96    TJ        1334727 Truning stationery into document
  32.                                     can cause it to disappeare!
  33.         <29>     6/21/96    jpa        1358818: Use "File" menu title in CyberDog.
  34.                                     1358820: Open "New" doc in same process in
  35.                                     CD. 1341242: (CL) Shouldn't be able to
  36.                                     activate windows w/modal dialog up
  37.         <28>     6/20/96    JP        1339269: Made quit handle the saving
  38.                                     parameter too
  39.         <27>     6/19/96    jpa        1357406: Call MMOverridePlatform in
  40.                                     Initialize method.
  41.         <26>     6/18/96    NP        1330731: Default stationery checkbox to
  42.                                     setting of Document Info.
  43.         <25>     6/14/96    eeh        1322456: check all frags in container
  44.         <24>     6/12/96    eeh        1315197: call parts' adjustMenus when F-key
  45.                                     pressed
  46.         <23>      6/7/96    eeh        T10017: function ptrs must be extern C
  47.         <22>      6/7/96    eeh        T10017: return CFM errors
  48.         <21>      6/7/96    eeh        T10017: call Dialogs lib instead of
  49.                                     DraftsWindow
  50.         <20>      6/5/96    EL        1355529: Use InitKindsPopUp in InfoUtil so
  51.                                     it don't need to be duplicated.
  52.         <19>    .06.1996    NP        10002: Launch time fixes, system process.
  53.         <18>     5/31/96    jpa        T10012: CyberDog process model (changes to
  54.                                     OpenFile, etc.)
  55.         <17>     5/24/96    JA        1246074: Native exception compatibility.
  56.         <16>    .05.1996    NP        1352438: Factor IsOptionKeyDown and
  57.                                     IsAnyKeyDown
  58.         <15>      5/8/96    NP        1282265: saving as stationery looks like
  59.                                     document
  60.         <14>      5/1/96    JA        1213332: Force 68K struct alignment of
  61.                                     'cfrg'. Init MW profiler.
  62.         <13>    .04.1996    NP        1286751: Present alert when trying to use
  63.                                     Open… when no Finder is running.
  64.         <12>      4/4/96    NP        1338241: If shell is in infinite loop,
  65.                                     quit.
  66.         <11>      4/2/96    RA        1320667: Call
  67.                                     Activate/DeactivateFrontWindows around
  68.                                     ShowAboutScreen modal dialog call
  69.         <10>     3/29/96    DM        1334273: propagate fatal Bento errors and
  70.                                     show low mem alert and quit when
  71.                                     out-of-memory err occurs while trying to
  72.                                     show low memory alert (solving infinite
  73.                                     loop).
  74.          <9>     3/22/96    CC        1307182: UpdateMenus: Check for null edit
  75.                                     menu.
  76.          <8>    .03.1996    NP        1307182: Stuff for caching shell menu
  77.                                     items.
  78.          <7>     3/20/96    EL        1331460 Save a Copy does not include the
  79.                                     resources in parent document (e.g.
  80.                                     preferred memory size)
  81.          <6>     3/14/96    NP        1287354: Hide invisible files in the Open
  82.                                     Document dialog.
  83.          <5>    .03.1996    NP        1223399: Don't show error dialog while
  84.                                     suspending.
  85.          <4>    .03.1996    NP        1304875,1317218: Fix can't-cancel problem
  86.                                     on receipt of quit event.
  87.          <3>      3/1/96    JP        1314798: Made new documents run from temp
  88.                                     file
  89.          <2>      1/4/96    eeh        1302569: handle fat plugins
  90.          
  91.     In Progress:
  92.         
  93. */
  94. #define _USE_DIALOGS_LIB_
  95.  
  96. #ifndef _PLFMDEF_
  97. #include <PlfmDef.h>
  98. #endif
  99.  
  100. #ifndef _SHELLDEF_
  101. #include "ShellDef.h"
  102. #endif
  103.  
  104. #ifndef _SHLMAIN_
  105. #include "ShlMain.h"
  106. #endif
  107.  
  108. #ifndef _DOCUTILS_
  109. #include "DocUtils.h"
  110. #endif
  111.  
  112. #ifndef _UTILDEFS_
  113. #include "UtilDefs.h"
  114. #endif
  115.  
  116. #ifndef _RLSHELL_
  117. #include "RlShell.h"
  118. #endif
  119.  
  120. #ifndef _SHPLUGIN_
  121. #include "ShPlugIn.h"
  122. #endif
  123.  
  124. #ifndef _BENTODEF_
  125. #include "BentoDef.h"
  126. #endif
  127.  
  128. #ifndef _USERSRCM_
  129. #include <UseRsrcM.h>
  130. #endif
  131.  
  132. #ifndef _EXCEPT_
  133. #include <Except.h>
  134. #endif
  135.  
  136. #ifndef SOM_Module_OpenDoc_Commands_defined
  137. #include <CmdDefs.xh>
  138. #endif
  139.  
  140. #ifndef _ODUTILS_
  141. #include <ODUtils.h>
  142. #endif
  143.  
  144. #ifndef _BINDNGH_
  145. #include <BindngH.h>
  146. #endif
  147.  
  148. #ifndef _BNDNSUTL_
  149. #include <BndNSUtl.h>
  150. #endif
  151.  
  152. #ifndef _TEMPOBJ_
  153. #include "TempObj.h"
  154. #endif
  155.  
  156. #ifndef _TEMPITER_
  157. #include "TempIter.h"
  158. #endif
  159.  
  160. #ifndef _ODMEMORY_
  161. #include <ODMemory.h>
  162. #endif
  163.  
  164. #ifndef _BARRAY_
  165. #include <BArray.h>
  166. #endif
  167.  
  168. #ifndef SOM_ODDispatcher_xh
  169. #include <Disptch.xh>
  170. #endif
  171.  
  172. #ifndef SOM_ODWindowState_xh
  173. #include <WinStat.xh>
  174. #endif
  175.  
  176. #ifndef SOM_ODWindowIterator_xh
  177. #include <WinIter.xh>
  178. #endif
  179.  
  180. #ifndef SOM_ODWindow_xh
  181. #include <Window.xh>
  182. #endif
  183.  
  184. #ifndef SOM_ODMenuBar_xh
  185. #include <MenuBar.xh>
  186. #endif
  187.  
  188. #ifndef _ORDCOLL_
  189. #include "OrdColl.h"
  190. #endif
  191.  
  192. #ifndef SOM_ODFrame_xh
  193. #include <Frame.xh>
  194. #endif
  195.  
  196. #ifndef SOM_ODFrameFacetIterator_xh
  197. #include <FrFaItr.xh>
  198. #endif
  199.  
  200. #ifndef SOM_Module_Apple_defined
  201. #include <Part.xh>
  202. #endif
  203.  
  204. #ifndef SOM_ODArbitrator_xh
  205. #include <Arbitrat.xh>
  206. #endif
  207.  
  208. #ifndef SOM_Module_OpenDoc_Foci_defined
  209. #include "Foci.xh"
  210. #endif
  211.  
  212. #ifndef SOM_ODSession_xh
  213. #include <ODSessn.xh>
  214. #endif
  215.  
  216. #ifndef SOM_ODLinkManager_xh
  217. #include <LinkMgr.xh>
  218. #endif
  219.  
  220. #ifndef SOM_ODStorageSystem_xh
  221. #include <ODStor.xh>
  222. #endif
  223.  
  224. #ifndef SOM_ODStorageUnit_xh
  225. #include <StorageU.xh>
  226. #endif
  227.  
  228. #ifndef SOM_ODDocument_xh
  229. #include <Document.xh>
  230. #endif
  231.  
  232. #ifndef SOM_ODContainer_xh
  233. #include <ODCtr.xh>
  234. #endif
  235.  
  236. #ifndef SOM_ODClipboard_xh
  237. #include <Clipbd.xh>
  238. #endif
  239.  
  240. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  241. #include <StdTypes.xh>
  242. #endif
  243.  
  244. #ifndef SOM_Module_OpenDoc_StdProps_defined
  245. #include <StdProps.xh>
  246. #endif
  247.  
  248. #ifndef _ITEXT_
  249. #include <IText.h>
  250. #endif
  251.  
  252. #ifndef _ISOSTR_
  253. #include <ISOStr.h>
  254. #endif
  255.  
  256. #ifndef _PASCLSTR_
  257. #include <PasclStr.h>
  258. #endif
  259.  
  260. #ifndef _STORUTIL_
  261. #include <StorUtil.h>
  262. #endif
  263.  
  264. #ifndef SOM_ODUndo_xh
  265. #include <Undo.xh>
  266. #endif
  267.  
  268. #ifndef SOM_ODInfo_xh
  269. #include <Info.xh>
  270. #endif
  271.  
  272. #ifndef _USE_DIALOGS_LIB_
  273. #ifndef _DRAFTWN_
  274. #include "DraftWn.h"
  275. #endif
  276. #endif
  277.  
  278. #ifndef _ODPRCS_
  279. #include "ODPrcs.h"
  280. #endif
  281.  
  282. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  283. #include <StdDefs.xh>
  284. #endif
  285.  
  286. #ifndef _INFOUTIL_
  287. #include <InfoUtil.h>
  288. #endif
  289.  
  290. #ifndef SOM_Module_OpenDoc_StandardExtensions_defined
  291. #include <StdExts.xh>
  292. #endif
  293.  
  294. #ifndef _STDTYPIO_
  295. #include <StdTypIO.h>
  296. #endif
  297.  
  298. #ifndef _DLOGUTIL_
  299. #include <DlogUtil.h>
  300. #endif
  301.  
  302. #ifndef _MEMMGR_
  303. #include <MemMgr.h>
  304. #endif
  305.  
  306. #if ODDebug
  307. #ifndef _MEMDEBG_
  308. #include <MemDebg.h>
  309. #endif
  310. #endif
  311.  
  312. #ifndef __QUICKDRAW__
  313. #include <QuickDraw.h>
  314. #endif
  315.  
  316. #ifndef __STANDARDFILE__
  317. #include <StandardFile.h>
  318. #endif
  319.  
  320. #ifndef __FOLDERS__
  321. #include <Folders.h>
  322. #endif
  323.  
  324. #ifndef __FONTS__
  325. #include <Fonts.h>
  326. #endif
  327.  
  328. #ifndef __MENUS__
  329. #include <Menus.h>
  330. #endif
  331.  
  332. #ifndef __OSEVENTS__
  333. #include <OSEvents.h>
  334. #endif
  335.  
  336. #ifndef __DIALOGS__
  337. #include <Dialogs.h>
  338. #endif
  339.  
  340. #ifndef __PACKAGES__
  341. #include <Packages.h>
  342. #endif
  343.  
  344. #ifndef __TOOLUTILS__
  345. #include <ToolUtils.h>
  346. #endif
  347.  
  348. #ifndef __DESK__
  349. #include <Desk.h>
  350. #endif
  351.  
  352. #ifndef __RESOURCES__
  353. #include <Resources.h>
  354. #endif
  355.  
  356. #ifndef __LOWMEM__
  357. #include <LowMem.h>
  358. #endif
  359.  
  360. #ifndef __GESTALTEQU__
  361. #include <GestaltEqu.h>
  362. #endif
  363.  
  364. #ifndef __SCRIPT__
  365. #include <Script.h>
  366. #endif
  367.  
  368. #ifndef __FINDER__
  369. #include <Finder.h>
  370. #endif
  371.  
  372. #ifndef __FILES__
  373. #include <Files.h>
  374. #endif
  375.  
  376. #ifndef __ICONS__
  377. #include <Icons.h>
  378. #endif
  379.  
  380. #ifndef __ALIASES__
  381. #include <Aliases.h>
  382. #endif
  383.  
  384. #ifndef __TEXTSERVICES__
  385. #include <TextServices.h>
  386. #endif
  387.  
  388. #ifndef __LIMITS__
  389. #include <limits.h>
  390. #endif
  391.  
  392. #ifndef __STRING__
  393. #include <string.h>
  394. #endif
  395.  
  396. #ifndef SOM_ODPartWrapper_xh
  397. #include "PartWrap.xh"
  398. #endif
  399.  
  400. #ifndef __STDIO__
  401. #include <stdio.h>
  402. #endif
  403.  
  404. #ifndef __SEGLOAD__
  405. #include "SegLoad.h"
  406. #endif
  407.  
  408. #ifndef _ODDEBUG_
  409. #include "ODDebug.h"
  410. #endif
  411.  
  412. #ifndef _MEMMGR_
  413. #include "MemMgr.h"
  414. #endif
  415.  
  416. #ifndef _MEMDEBG_
  417. #include "MemDebg.h"
  418. #endif
  419.  
  420. #ifndef _STORUTIL_
  421. #include <StorUtil.h>
  422. #endif
  423.  
  424. #ifndef _NMSPCUTL_
  425. #include <NmSpcUtl.h>
  426. #endif
  427.  
  428. #ifndef SOM_ODBinding_xh
  429. #include <ODBindng.xh>
  430. #endif
  431.  
  432. #ifndef SOM_ODTranslation_xh
  433. #include <Translt.xh>
  434. #endif
  435.  
  436. #ifndef SOM_ODTypeList_xh
  437. #include <TypeList.xh>
  438. #endif
  439.  
  440. #ifndef SOM_ODTypeListIterator_xh
  441. #include <TypLsItr.xh>
  442. #endif
  443.  
  444. #ifndef _SIHELPER_
  445. #include <SIHelper.h>
  446. #endif
  447.  
  448. #ifndef _EDITRSET_
  449. #include <EditrSet.h>
  450. #endif
  451.  
  452. #ifndef _TRANSUTL_
  453. #include <TransUtl.h>
  454. #endif
  455.  
  456. #ifndef _CRAWL_
  457. #include <Crawl.h>
  458. #endif
  459.  
  460. #ifndef _SEUTILS_
  461. #include "SEUtils.h"
  462. #endif
  463.  
  464. #ifndef __EDITIONS__
  465. #include <Editions.h>
  466. #endif
  467.  
  468. #ifndef __CODEFRAGMENTS__
  469. #include <CodeFragments.h>
  470. #endif
  471.  
  472. #ifndef _CONSTDEF_
  473. #include <ConstDef.h>
  474. #endif
  475.  
  476. #ifndef _SHELLMEM_
  477. #include <ShellMem.h>
  478. #endif
  479.  
  480. #ifndef _ERRUTILS_
  481. #include <ErrUtils.h>
  482. #endif
  483.  
  484. #ifndef _ODXDPFNS_
  485. #include <ODXDpFns.h>
  486. #endif
  487.  
  488. #ifdef __MWERKS__
  489. #if __option(profile)
  490. #include <profiler.h>
  491. #endif
  492. #endif
  493.  
  494. #pragma segment RealShell
  495.  
  496. #if ODDebug
  497. //==============================================================================
  498. // Debugging #Defines
  499. //==============================================================================
  500.  
  501. #endif
  502.  
  503. //==============================================================================
  504. // Constants
  505. //==============================================================================
  506.  
  507. // <eeh> this should be defined elsewhere, so that parts like EditorSetup can
  508. // use it rather than risk choosing another constant.
  509. const  ODMenuID  kODAppleMenuID  = 255;
  510. const  ODMenuID  kODDocumentMenuID  = 256;
  511. const  ODMenuID  kODEditMenuID    = 257;
  512. const  ODOSType  kODDASMenuRsrc    = 0x44525652; // 'DRVR';
  513.  
  514. const ODSLong    kMaxTimeBetweenLocationChecks = 3 * 60L;    // Background file check delay
  515.  
  516. const short kMaxUniqueNameTries = 100;
  517.  
  518.  
  519. const ODSShort    kUseSpecificScript = 0x1c;
  520.  
  521. #define kMaxNumberSuffixLength 11
  522.  
  523. // For window resizing
  524. #define kMinWindowWidth  192
  525. #define kMinWindowHeight 64
  526. #define kMaxWindowWidth  16384
  527. #define kMaxWindowHeight 16384
  528.  
  529. // from DrawDef.h
  530. #define kODKindTestDraw "Apple:Kind:TestDraw"
  531.  
  532. // Local error codes:
  533.  
  534. #define        kODErrClosingNonODWindow    5001
  535.  
  536.  
  537. #define ODDebugMenu ODDebug        /* Use Debug menu if debug build */
  538.  
  539.  
  540. #if ODDebugMenu
  541. const ODMenuID kDebugMenuID = 100;
  542. // Command IDs for the debugging menu:
  543. enum {
  544.     kODCommandDBHeapInfo = 980,
  545.     kODCommandDBDumpObjects,
  546.     kODCommandDBDumpBlocks,
  547.     kODCommandDBMemValidation,
  548.     kODCommandDBHeapChecking,
  549.     kODCommandDBLeakChecking,
  550.     kODCommandDBDumpBlocksOnClose,
  551.     kODCommandDBTrackStackCrawls,
  552.     kODCommandDBLogStdout,
  553.     kODCommandDBLogDebugWindow,
  554.     kODCommandDBLogDebugStr,
  555.     kODCommandDBSOMTrace,
  556.     kODCommandDBBreakOnThrow,
  557.     kODCommandDBEatMemory,
  558.     kODCommandDBPurge
  559. };
  560.  
  561. const short kODHeapInfoAlert = 980;
  562. #endif
  563.  
  564. const StringPtr kODEmptyPString = "\p";
  565.  
  566. //==============================================================================
  567. // Local Macros
  568. //==============================================================================
  569.  
  570. #if ODDebug
  571. #define SHLDebugStr(x)        DebugStr(x)
  572. #else
  573. #define SHLDebugStr(x)
  574. #endif
  575.  
  576. #define BITTEST( codes, thisCode )                                            \
  577.         (((codes) & (thisCode)) != 0L)
  578.  
  579. //#define SHLHeapDebug
  580. //#define SHLTestSessionOverhead
  581. //#define SHLTestErrorDialogUsage
  582.  
  583. //==============================================================================
  584. // Static variables
  585. //==============================================================================
  586.  
  587. #if ODDebug
  588. static ODBoolean gMemValidation = kODFalse;
  589. static ODBoolean gHeapChecking    = kODFalse;
  590. static ODBoolean gLeakChecking  = kODFalse;
  591. static ODBoolean gDumpBlocksOnClose      = kODFalse;
  592. static ODBoolean gTrackStackCrawls  = kODFalse;
  593. #endif
  594.  
  595. #ifndef __MWERKS__
  596. QDGlobals qd;
  597. #endif            
  598. // Need to declare 'qd' ourselves because even though 'qd' is already 
  599. // in Startup.c in the Metrowerks libraries, it is NOT necessarily in the
  600. // libraries for other compilers, e.g the compilers for CFM68K. -TÇ
  601.  
  602. //==============================================================================
  603. // Local Classes
  604. //==============================================================================
  605.  
  606. struct ErrRecord
  607. {
  608.     ODError lowErr, highErr;
  609.     ODULong index;
  610. };
  611.  
  612. typedef ErrRecord* ErrRecordPointer;
  613. typedef ErrRecordPointer* ErrRecordHandle;
  614.  
  615. //==============================================================================
  616. // Function Prototype
  617. //==============================================================================
  618.  
  619. void    CreateTempName(short seed, Str255 name, ODBoolean isFile);
  620.     // $opt: CreateTempName is duplicated in ODPrcs.cpp
  621.     
  622. void    GetTempFolder(ODSShort* VRef,ODSLong* DirID);
  623. void    CreateNewFile(PlatformFile* newFile, ODBoolean forceNewName); // newFile is in/out
  624.  
  625. pascal void DrawSmallIcon(DialogPtr theDialog, short theItem);
  626. pascal short SaveCopyDlgHook(short item, DialogPtr theDialog, void *yourDataPtr);
  627.  
  628. #if ODDebug
  629. static ODBoolean isHeapKeyDown();
  630.  
  631. static ODBoolean isFilterKeyDown();
  632.  
  633. static void HeapInfo();
  634.  
  635. #endif
  636.  
  637. ODStatic void FindShellPlugInsFolder(short *vol, long *dir );
  638. ODStatic void FindStationeryFolder(short *vol, long *dir );
  639.                              
  640. ODStatic void    CreateNewUntitledFile(PlatformFile* newFile, 
  641.                         char* fileNameSeed = kODNULL);
  642. // Note: fileNameSeed is ignored if newFile->IsStationery()
  643.  
  644. static ODIText* CreateDefaultIText(StringPtr text);
  645. static OSErr SendFinderODOCEvent( const FSSpec *fileToOpen );
  646. ODStatic OSErr GetCfrgInfo( ODFileSpec* fileSpec, long* offset, long* length );
  647. ODStatic void    CopyResources(PlatformFile* srcFile, PlatformFile* dstFile);
  648.             
  649.  
  650. extern ODBoolean gODBentoFatalErrorHasOccurred; // SessHdr.cpp
  651. extern ODBoolean gODDelayBentoFatalError; // SessHdr.cpp
  652. extern ODBoolean gODSuppressBentoFatalError; // SessHdr.cpp
  653. extern void ODBentoFatalError(ODBoolean allowSuppress); // SessHdr.cpp
  654.                              
  655. #if ODDebug
  656. static void DumpHeapObjects( ODBoolean objectsOnly );
  657. #endif
  658.                              
  659. void FinderNotRunning();
  660.  
  661. //==============================================================================
  662. // ShellMain Function
  663. //==============================================================================
  664.  
  665. #pragma lib_export on            // only ShellMain needs to be exported
  666.  
  667. #ifdef __cplusplus
  668. extern "C" {
  669. #endif
  670.  
  671. int ShellMain()
  672. {
  673.     MaxApplZone();
  674.     MoreMasters();
  675.     MoreMasters();
  676.     MoreMasters();
  677.     MoreMasters();        // $Opt: May need more of these. Poke about at runtime to see.
  678.  
  679.     InitGraf(&qd.thePort);
  680.  
  681.     InitFonts();
  682.     FlushEvents(everyEvent, 0);
  683.     InitWindows();
  684.     InitMenus();
  685.     TEInit();
  686.     InitDialogs(kODNULL);
  687.     WatchCursor();
  688.  
  689.     // Intialize Metrowerks profiler if this is a profiling build:
  690. #ifdef __MWERKS__
  691. #if __option(profile)
  692.     ProfilerInit(collectDetailed,bestTimeBase,3000,100);
  693.     ProfilerSetStatus(false);
  694. #endif
  695. #endif
  696.  
  697. /* Note below that we continue even if the Edition Manager or TSM are not around. 
  698.    There is no express reason that either one of these need to be around for OpenDoc
  699.    in general to function.  Lack of Edition Manager just means you can't do linking.
  700.  */
  701.  
  702.     if (InitEditionPack() != noErr)
  703.         SHLDebugStr("\pInitEditionPack failed");
  704.  
  705.     long gestaltResponse;
  706.     ODBoolean hasTSM = (Gestalt(gestaltTSMgrVersion, &gestaltResponse) == noErr) &&
  707.          (gestaltResponse >= 1);
  708.     if (hasTSM)
  709.     {
  710.         if (InitTSMAwareApplication() == noErr)
  711.         {
  712.             const TSMDocumentID    kAnyDoc = kODNULL;
  713.         
  714.             if (UseInputWindow(kAnyDoc, kODTrue) != noErr)
  715.                 SHLDebugStr("\pUseInputWindow failed.");
  716.         }
  717.         else
  718.         {
  719.             SHLDebugStr("\pInitTSMAwareApplication failed.");
  720.         }
  721.     }
  722.     else
  723.     {
  724.         SHLDebugStr("\pTSM unavailable.");
  725.     }
  726.     
  727.     TRY
  728.         ODInitExceptions();        // Sets up SOMError and SOMPrintf
  729.     
  730.     // CHECK FOR RUNNING UNDER MacOS8
  731.     {
  732.         CUsingLibraryResources    r;
  733.  
  734.         if (RunningUnderMacOS8())
  735.             return 1;
  736.     }
  737.  
  738.     #if ODDebug
  739.         MMBeginMemValidation();
  740.         gMemValidation = kODTrue;
  741.     #endif
  742.     
  743.     #if VALIDATE_EVERYTHING
  744.         // MMBeginMemValidation(); Should be taken care of by above.
  745.         MMBeginHeapChecking( );
  746.     #endif
  747.     
  748.         if (IsOptionKeyDown())
  749.             SHLDebugStr("\pAbout to create and enter the Shell.  You may proceed.");
  750.         
  751.     #if ODDebug
  752.         if (isHeapKeyDown())
  753.         {
  754.             SHLDebugStr("\pAbout to track heap block stack crawls. Type g to proceed.");
  755.             gDumpBlocksOnClose = kODTrue;
  756.             gTrackStackCrawls = kODTrue;
  757.         }
  758.     #endif
  759.         
  760.         RealShell*    le = new RealShell;
  761.         le->go();
  762.         delete le;
  763.         
  764.     #if VALIDATE_EVERYTHING
  765.         MMEndHeapChecking( );
  766.         MMEndMemValidation();
  767.     #endif
  768.     
  769.         if (hasTSM)
  770.             CloseTSMAwareApplication();
  771.     CATCH_ALL
  772.         /* Not much we can do here folks.
  773.            Either ODInitExceptions failed, or creating a RealShell object failed.
  774.            If the latter, then we don't have enough memory to put up a dialog.
  775.            If the former, then something is really wrong the runtime.
  776.          */
  777.         SHLDebugStr("\pException reached ShellMain. Possibly ODInitExceptions failed");
  778.     ENDTRY
  779.  
  780.     return 0;
  781. }
  782.  
  783. #ifdef __cplusplus
  784. }
  785. #endif
  786.  
  787. #pragma lib_export off
  788.  
  789. //==============================================================================
  790. // Static Functions
  791. //==============================================================================
  792.  
  793. #if ODDebug
  794. static ODBoolean isHeapKeyDown() // use 'h' to mean "heap"
  795. {
  796.     const ODUShort heapKey = 4;    // the 'h' key
  797.     return IsThisKeyDown(heapKey);
  798. }
  799. static ODBoolean isFilterKeyDown() // use 'f' to mean "filter"
  800. {
  801.     const ODUShort filterKey = 3;    // the 'f' key
  802.     return IsThisKeyDown(filterKey);
  803. }
  804. #endif
  805.  
  806. #if ODDebug
  807.  
  808. static void
  809. ParamTextHeapInfo( )
  810. {
  811.     const char *name;
  812.     size_t allocated, free,blocks,objects,contig;
  813.     
  814.     MMGetHeapInfo(kDefaultHeapID,
  815.                   &name, &allocated, &free, &blocks, &objects);
  816.     char nameStr[256], infoStr[256], appInfoStr[256];
  817.     strcpy((char*)nameStr, name);
  818.     sprintf(infoStr,"%lu\r%lu (%.1f%%)\r%lu (%lu objs)",
  819.             allocated, free,
  820.             100.0*free/(float)(allocated+free),
  821.             blocks,objects);
  822.  
  823.     MMSystemFreeSpace(kMMAppMemory, &free,&contig);
  824.     allocated = (ApplicationZone()->bkLim-(Ptr)&ApplicationZone()->heapData) - free;
  825.     sprintf(appInfoStr,"%lu\r%lu (%.1f%%)\r%lu",
  826.             allocated, free,
  827.             100.0*free/(float)(allocated+free),
  828.             contig);
  829.  
  830.     ParamText(CToPascalString(nameStr),CToPascalString(infoStr),
  831.               "\pMacOS Application Heap",CToPascalString(appInfoStr));
  832. }
  833.  
  834. static void HeapInfo()
  835. {
  836.     ParamTextHeapInfo();
  837.     ODSLong        savedRefNum;
  838.     BeginUsingLibraryResources(savedRefNum);
  839.     NoteAlert(kODHeapInfoAlert, NULL);
  840.     EndUsingLibraryResources(savedRefNum);
  841. }
  842.  
  843. #endif
  844.  
  845.  
  846. //==============================================================================
  847. // RealShell
  848. //==============================================================================
  849.  
  850.  
  851. //-------------------------------------------------------------------------------------
  852. // Initialization
  853. //-------------------------------------------------------------------------------------
  854.  
  855. RealShell::RealShell()
  856. {
  857.     fEV         = kODNULL;
  858.     fSession                 = kODNULL;
  859.     fDispatcher             = kODNULL;
  860.     fWindowState            = kODNULL;
  861.     fArbitrator                = kODNULL;
  862.     fSIHelper                = kODNULL;
  863.  
  864.     fModalFocusToken        = kODNullTypeToken;
  865.     fAlreadyInCoercion        = kODFalse;
  866.     fErrorFromOpenEvents    = noErr;
  867.     fUniqueNameSeed            = 1;
  868.     fShellHasMenuFocus        = kODFalse;
  869.     fLastNewDocPSN.lowLongOfPSN = kNoProcess;
  870.  
  871.     fSaveCopyData            = kODNULL;
  872.     fSaveDiffVolDialog        = kODNULL;
  873.     
  874.     fLowMemNotified            = kODFalse;
  875.     
  876.     fFailedPlugInName[0]    = 0;
  877. }
  878.  
  879.  
  880. RealShell::~RealShell()
  881. {
  882.     
  883.     ODDeleteObject(fSIHelper);
  884.     
  885.     this->ExportClipboard(kODFalse);
  886. #ifdef SHLHeapDebug
  887.     SHLDebugStr("\pPostCloseDoc/PreSessionDelete HeapInfo…");
  888.     HeapInfo();
  889. #endif
  890.     delete fSession;
  891. #ifdef SHLHeapDebug
  892.     SHLDebugStr("\pPostSessionDelete HeapInfo…");
  893.     HeapInfo();
  894. #endif
  895.  
  896. #if ODDebug
  897.     if( gDumpBlocksOnClose ) {
  898.         somPrintf("SOM objects and tracked blocks in heap contents after closing the session:\n");
  899.         DumpHeapObjects(/*objectsOnly*/ kODFalse);
  900.     }
  901. #endif
  902.     WASSERT(fSaveDiffVolDialog==kODNULL);
  903. }
  904.  
  905.  
  906.  
  907. void RealShell::Initialize()
  908. {
  909.     // Force NewPtr to allocate in our heap in temp mem. This fixes the problem
  910.     // of CFM global data choking the app heap!
  911.     MMOverridePlatform(kODTrue,kODFalse);
  912.     
  913.     fEV = somGetGlobalEnvironment();
  914.         
  915.     fSession = new ODSession;
  916.     THROW_IF_NULL(fSession); // som objects don't autothrow if unable to allocate.
  917.     fSession->InitSession(fEV);
  918.     // Note: we need fDispatcher & fWindowState BEFORE ShellPlugIns are installed.
  919.     fDispatcher = fSession->GetDispatcher(fEV);
  920.     fWindowState = fSession->GetWindowState(fEV);
  921.     fArbitrator = fSession->GetArbitrator( fEV );
  922.  
  923.     fModalFocusToken = fSession->Tokenize( fEV, kODModalFocus );
  924.         
  925.     // Is the app curently the active process?
  926.     ProcessSerialNumber me = {0,kCurrentProcess};
  927.     ProcessSerialNumber cur;
  928.     GetFrontProcess(&cur);
  929.     SameProcess(&me,&cur,&fProcessIsActive);
  930.     
  931.     // Is this an APPL process or a normal OD doc process?
  932.     ProcessInfoRec info;
  933.     this->GetCurrentProcessInfo(&info);
  934.     fAPPLProcess = (info.processType=='APPL');
  935.  
  936.     this->InstallMenuBar();
  937.     this->InitAE();
  938.     this->InitMemory();
  939. }
  940.  
  941. void RealShell::InstallMenuBar()
  942. {
  943.     ODSLong        savedRefNum;
  944.     BeginUsingLibraryResources(savedRefNum);
  945.  
  946.     ODPlatformMenuBar    menuBar;
  947.     menuBar = GetNewMBar(kODAppleMenuID);
  948.     
  949.     if( !menuBar ) THROW(resNotFound);
  950.     SetMenuBar(menuBar);
  951.  
  952.     MenuHandle appleMenu = GetMenuHandle(kODAppleMenuID);
  953.     DetachResource((Handle)appleMenu);
  954.     
  955. #if ODDebugMenu
  956.     // Add "ODDebug" menu item, with submenu, below "About..." command:
  957.     InsertMenuItem(appleMenu,"\pODDebug",1);
  958.     SetItemCmd(appleMenu,2,0x1B);
  959.     SetItemMark(appleMenu,2, kDebugMenuID);
  960.     
  961.     MenuHandle dbMenu = NewMenu(kDebugMenuID,"\pODDebug");
  962.     THROW_IF_NULL(dbMenu);
  963.     AppendMenu(dbMenu,    "\pHeap Info;"
  964.                         "Memory Validation;"
  965.                         "Heap Checking;"
  966.                         "Leak Checking;"
  967.                         "Dump Blocks On Close;"
  968.                         "Track Block Stack Crawls;"
  969.                         "Eat Memory;"
  970.                         "Purge;"
  971.                         "(-;"
  972.                         "Log To stdout File;"
  973.                         "Log To DebugWindow;"
  974.                         "Generate DebugStrs;"
  975.                         "Dump ODObjects;"
  976.                         "Dump Tracked Blocks;"
  977.                         "(-;"
  978.                         "Break On THROW;"
  979.                         "SOM Trace" );
  980.     InsertMenu(dbMenu,hierMenu);
  981.  
  982.     const int kNumDebugMenuItems = 17;
  983.  
  984.     static const ODCommandID kDBCommands[kNumDebugMenuItems] = {kODCommandDBHeapInfo,
  985.                                                 kODCommandDBMemValidation,
  986.                                                 kODCommandDBHeapChecking,
  987.                                                 kODCommandDBLeakChecking,
  988.                                                 kODCommandDBDumpBlocksOnClose,
  989.                                                 kODCommandDBTrackStackCrawls,
  990.                                                 kODCommandDBEatMemory,
  991.                                                 kODCommandDBPurge,
  992.     /* Used below... */                            0,
  993.                                                 kODCommandDBLogStdout,
  994.                                                 kODCommandDBLogDebugWindow,
  995.                                                 kODCommandDBLogDebugStr,
  996.                                                 kODCommandDBDumpObjects,
  997.                                                 kODCommandDBDumpBlocks,
  998.                                                 0,
  999.                                                 kODCommandDBBreakOnThrow,
  1000.                                                 kODCommandDBSOMTrace};
  1001.  
  1002.     DisposeHandle((Handle)menuBar);                // Update menuBar variable with new menu
  1003.     menuBar = GetMenuBar();
  1004. #endif
  1005.     
  1006.     // create a new ODMenuBar object
  1007.     TempODMenuBar baseMenuBar = fWindowState->CreateMenuBar(fEV, menuBar);
  1008.     
  1009.     // add DA names to Apple menu
  1010.     AppendResMenu(appleMenu, kODDASMenuRsrc);
  1011.  
  1012. #ifdef SUPPORT_QUIT
  1013.     // Load Document menu, or File menu if running in an 'APPL' process: [MenuIDs are identical!]
  1014.     MenuHandle documentMenu = GetMenu( fAPPLProcess ?kODFileMenuID :kODDocumentMenuID);
  1015. #else
  1016.     MenuHandle documentMenu = GetMenu(kODDocumentMenuID);
  1017. #endif
  1018.  
  1019.     DetachResource((Handle)documentMenu);
  1020.  
  1021.     baseMenuBar->AddMenuLast(fEV, kODDocumentMenuID, documentMenu, kODNULL);
  1022.  
  1023.     MenuHandle editMenu = GetMenu(kODEditMenuID);
  1024.     DetachResource((Handle)editMenu);
  1025.     baseMenuBar->AddMenuLast(fEV, kODEditMenuID, editMenu, kODNULL);
  1026.  
  1027. //    Save off the default undo and redo menu items so that we can use them when
  1028. //    there's nothing on the undo or redo stack.
  1029.  
  1030.     this->SaveMenuItem(appleMenu, kSHLMenuAbout, &fDefaultAboutMenuItem);
  1031.     this->SaveMenuItem(editMenu, kSHLMenuUndo, &fDefaultUndoMenuItem);
  1032.     this->SaveMenuItem(editMenu, kSHLMenuRedo, &fDefaultRedoMenuItem);
  1033.     this->SaveMenuItem(editMenu, kSHLMenuPreferences, &fDefaultPrefsMenuItem);
  1034.  
  1035.      EndUsingLibraryResources(savedRefNum);
  1036.  
  1037.     baseMenuBar->RegisterCommand(fEV, kODCommandAppleMenu, kODAppleMenuID, 0);
  1038.     baseMenuBar->RegisterCommand(fEV, kODCommandAbout, kODAppleMenuID, kSHLMenuAbout);
  1039.     
  1040.     baseMenuBar->RegisterCommand(fEV, kODCommandDocumentMenu, kODDocumentMenuID, 0);
  1041.     baseMenuBar->RegisterCommand(fEV, kODCommandNew, kODDocumentMenuID, kSHLMenuNew);
  1042.     baseMenuBar->RegisterCommand(fEV, kODCommandOpen, kODDocumentMenuID, kSHLMenuOpen);
  1043.     baseMenuBar->RegisterCommand(fEV, kODCommandOpenDocument, kODDocumentMenuID, kSHLMenuOpenDocument);
  1044.     baseMenuBar->RegisterCommand(fEV, kODCommandInsert, kODDocumentMenuID, kSHLMenuInsert);
  1045.     baseMenuBar->RegisterCommand(fEV, kODCommandClose, kODDocumentMenuID, kSHLMenuClose);
  1046.     baseMenuBar->RegisterCommand(fEV, kODCommandDeleteDocument, kODDocumentMenuID, kSHLMenuDeleteDocument);
  1047.     
  1048.     baseMenuBar->RegisterCommand(fEV, kODCommandSave, kODDocumentMenuID, kSHLMenuSave);
  1049.     baseMenuBar->RegisterCommand(fEV, kODCommandSaveACopy, kODDocumentMenuID, kSHLMenuSaveACopy);
  1050.     baseMenuBar->RegisterCommand(fEV, kODCommandRevert, kODDocumentMenuID, kSHLMenuRevert);
  1051.     baseMenuBar->RegisterCommand(fEV, kODCommandDraft, kODDocumentMenuID, kSHLMenuDraft);
  1052.     baseMenuBar->RegisterCommand(fEV, kODCommandDocumentInfo, kODDocumentMenuID, kSHLMenuDocumentInfo);
  1053.     
  1054.     baseMenuBar->RegisterCommand(fEV, kODCommandPageSetup, kODDocumentMenuID,
  1055.             kSHLMenuPageSetup );
  1056.     baseMenuBar->RegisterCommand(fEV, kODCommandPrint, kODDocumentMenuID,
  1057.             kSHLMenuPrint );
  1058.     
  1059. #ifdef SUPPORT_QUIT
  1060.     // If this is an APPL process like CyberDog, register "Quit" cmd
  1061.     if( fAPPLProcess )
  1062.         baseMenuBar->RegisterCommand(fEV, kODCommandQuit, kODDocumentMenuID, kSHLMenuQuit);
  1063. #endif
  1064.  
  1065.     baseMenuBar->RegisterCommand(fEV, kODCommandEditMenu, kODEditMenuID, 0);
  1066.     baseMenuBar->RegisterCommand(fEV, kODCommandUndo, kODEditMenuID, kSHLMenuUndo);
  1067.     baseMenuBar->RegisterCommand(fEV, kODCommandRedo, kODEditMenuID, kSHLMenuRedo);
  1068.     baseMenuBar->RegisterCommand(fEV, kODCommandCut, kODEditMenuID, kSHLMenuCut);
  1069.     baseMenuBar->RegisterCommand(fEV, kODCommandCopy, kODEditMenuID, kSHLMenuCopy);
  1070.     baseMenuBar->RegisterCommand(fEV, kODCommandPaste, kODEditMenuID, kSHLMenuPaste);
  1071.     baseMenuBar->RegisterCommand(fEV, kODCommandPasteAs, kODEditMenuID, kSHLMenuPasteAs);
  1072.     baseMenuBar->RegisterCommand(fEV, kODCommandClear, kODEditMenuID, kSHLMenuClear);
  1073.     baseMenuBar->RegisterCommand(fEV, kODCommandSelectAll, kODEditMenuID, kSHLMenuSelectAll);
  1074.     baseMenuBar->RegisterCommand(fEV, kODCommandGetPartInfo, kODEditMenuID, kSHLMenuGetPartInfo);
  1075.     baseMenuBar->RegisterCommand(fEV, kODCommandPreferences, kODEditMenuID, kSHLMenuPreferences);
  1076.     baseMenuBar->RegisterCommand(fEV, kODCommandViewAsWin, kODEditMenuID, kSHLMenuViewAsWin);
  1077.     
  1078. #if ODDebugMenu
  1079.     for( short i=0; i<kNumDebugMenuItems; i++ )
  1080.         if( kDBCommands[i] )
  1081.             baseMenuBar->RegisterCommand(fEV, kDBCommands[i], kDebugMenuID, i+1);
  1082. #endif
  1083.  
  1084.     fWindowState->SetBaseMenuBar(fEV,baseMenuBar);
  1085.     baseMenuBar->Display(fEV);
  1086. }
  1087.  
  1088. //------------------------------------------------------------------------------
  1089. // RealShell::SaveMenuItem
  1090. //------------------------------------------------------------------------------
  1091.  
  1092. void
  1093. RealShell::GetCurrentProcessInfo( ProcessInfoRec *info, StringPtr name, FSSpec *appLoc )
  1094. {
  1095.     ProcessSerialNumber psn = {0,kCurrentProcess};
  1096.     info->processInfoLength = sizeof(ProcessInfoRec);
  1097.     info->processName = name;
  1098.     info->processAppSpec = appLoc;
  1099.     THROW_IF_ERROR( GetProcessInformation(&psn,info) );
  1100. }
  1101.  
  1102.  
  1103. //------------------------------------------------------------------------------
  1104. // RealShell::SaveMenuItem
  1105. //------------------------------------------------------------------------------
  1106.  
  1107. void RealShell::SaveMenuItem(MenuHandle menu, short itemNum, MenuItemInfo* info)
  1108. {
  1109.     GetMenuItemText(menu, itemNum, (*info).text);
  1110.     GetItemCmd(menu, itemNum, &(*info).cmdChar);
  1111.     GetItemIcon(menu, itemNum, &(*info).iconID);
  1112.     GetItemMark(menu, itemNum, &(*info).markChar);
  1113.     GetItemStyle(menu, itemNum, &(*info).textStyle);
  1114. }
  1115.  
  1116. //------------------------------------------------------------------------------
  1117. // RealShell::RestoreMenuItem
  1118. //------------------------------------------------------------------------------
  1119.  
  1120. void RealShell::RestoreMenuItem(MenuHandle menu, short itemNum, MenuItemInfo* info)
  1121. {
  1122.     SetMenuItemText(menu, itemNum, (*info).text);
  1123.     SetItemCmd(menu, itemNum, (*info).cmdChar);
  1124.     SetItemIcon(menu, itemNum, (*info).iconID);
  1125.     SetItemMark(menu, itemNum, (*info).markChar);
  1126.     SetItemStyle(menu, itemNum, (*info).textStyle);
  1127. }
  1128.  
  1129. //------------------------------------------------------------------------------
  1130. // RealShell::InstallShellPlugIns
  1131. //------------------------------------------------------------------------------
  1132.  
  1133. void RealShell::InstallShellPlugIns(ODDraft* draft)
  1134. {
  1135.     // get reference to OpenDoc Shell PlugIns directory
  1136.     ODSShort fldrVRefNum=0;
  1137.     ODSLong fldrDirID=0;
  1138.  
  1139.     TRY{
  1140.         FindShellPlugInsFolder(&fldrVRefNum, &fldrDirID);
  1141.         this->ScanShellPlugInsFldr(fldrVRefNum, fldrDirID, draft);
  1142.     }CATCH_ALL{
  1143.         if ( fFailedPlugInName[0] )
  1144.             RERAISE;
  1145.     }ENDTRY
  1146.  
  1147. }
  1148.  
  1149. //------------------------------------------------------------------------------
  1150. // GetInstallEntryPt
  1151. // Given a file spec, find the record within the 'cfrg' resource in that
  1152. // file that corresponds to the platform we're on and the symbol we're
  1153. // looking for.  Loop through all entries until finding one that has
  1154. // the entry point we're looking for.
  1155. //------------------------------------------------------------------------------
  1156. ODStatic OSErr GetInstallEntryPt( ODFileSpec* fileSpec, ODShellPlugInInstallProc* entryPt,
  1157.         CFragConnectionID* connIDPtr )
  1158. {
  1159. #if PRAGMA_ALIGN_SUPPORTED
  1160. #pragma options align=mac68k
  1161. #endif
  1162.  
  1163.     struct FragDesc {
  1164.         ResType codeType;
  1165.         long ignore[5];
  1166.         long offsetToFrag;
  1167.         long lengthOfFrag;
  1168.         long moreIgnore[2];
  1169.         short recordLength;
  1170.         Str63 name;
  1171.     };
  1172.     
  1173.     struct CFRGResource {
  1174.         long ignore[7];
  1175.         long numFrags;
  1176.         struct FragDesc firstDesc;
  1177.     };
  1178.  
  1179. #if PRAGMA_ALIGN_SUPPORTED
  1180. #pragma options align=reset
  1181. #endif
  1182.  
  1183.     OSErr err = resNotFound;
  1184.  
  1185.     short refNum = HOpenResFile( fileSpec->vRefNum, fileSpec->parID,
  1186.             fileSpec->name, fsRdPerm );
  1187.     short saveRefNum = CurResFile();
  1188.     UseResFile( refNum );
  1189.  
  1190.     struct CFRGResource** cfrgHandle =
  1191.             (struct CFRGResource**)Get1Resource( 'cfrg', 0 );
  1192.     if ( cfrgHandle )
  1193.     {
  1194.         long entryCount = (*cfrgHandle)->numFrags;
  1195.         struct FragDesc* oneEntryPtr = &(*cfrgHandle)->firstDesc;
  1196.         while ( entryCount-- )
  1197.         {
  1198.             // for each fragment, if it's the right architecture
  1199.             // see if it has an entrypoint of the right name.
  1200.             // Keep going until found or all exhausted (bug 1322456)
  1201.             if ( oneEntryPtr->codeType == kCurrentCFragArch )
  1202.             {
  1203.                 CFragConnectionID connID;
  1204.                 Ptr ignoreMainAddr;
  1205.                 Str255 errName;
  1206.                 err = GetDiskFragment( fileSpec,
  1207.                         oneEntryPtr->offsetToFrag,
  1208.                         oneEntryPtr->lengthOfFrag,
  1209.                         NULL, kNewCFragCopy, &connID, &ignoreMainAddr,
  1210.                         errName );
  1211.                 if ( err == noErr )
  1212.                 {
  1213.                     ODShellPlugInInstallProc installMethod;
  1214.                     CFragSymbolClass symClass;
  1215.                     err = FindSymbol( connID, "\pODShellPlugInInstall",
  1216.                             (Ptr*)&installMethod, &symClass );
  1217.                     if ( err == noErr )            // we're done
  1218.                     {
  1219.                         WASSERT( symClass == kTVectorCFragSymbol );
  1220.                         *entryPt = installMethod;
  1221.                         *connIDPtr = connID;
  1222.                         break;
  1223.                     }
  1224.                     else    // we opened it but don't want it; free the memory
  1225.                         CloseConnection( &connID );
  1226.                 }
  1227.             }
  1228. //            else
  1229.                 oneEntryPtr = (FragDesc*)(oneEntryPtr->recordLength
  1230.                         + (char*)oneEntryPtr);
  1231.         }
  1232.     }
  1233.     else
  1234.         err = ResError();
  1235.  
  1236.     CloseResFile( refNum );
  1237.     UseResFile( saveRefNum );
  1238.     return err;
  1239. }    // GetInstallEntryPt()
  1240.  
  1241. //------------------------------------------------------------------------------
  1242. // RealShell::ScanShellPlugInsFldr
  1243. //------------------------------------------------------------------------------
  1244.  
  1245. void RealShell::ScanShellPlugInsFldr(ODSShort fldrVRefNum, ODSLong fldrDirID,
  1246.                                     ODDraft* draft)
  1247. {
  1248.     // iterate through files in that directory (code copied from Prefs.cpp:LoadNameSpaceTable)
  1249.     ODFileSpec        theFileSpec;
  1250.     CInfoPBRec        CinfoPB;
  1251.     Str255            fileName;
  1252.  
  1253.     memset (&CinfoPB,0,sizeof(CinfoPB));
  1254.     CinfoPB.hFileInfo.ioNamePtr = (StringPtr)fileName;
  1255.     CinfoPB.hFileInfo.ioFDirIndex = 1;
  1256.     CinfoPB.hFileInfo.ioVRefNum = fldrVRefNum;
  1257.     CinfoPB.hFileInfo.ioDirID = fldrDirID;
  1258.  
  1259.     TempPlatformFile file(new PlatformFile);
  1260.     
  1261.     for( ODSShort i = PBGetCatInfoSync( &CinfoPB ); 
  1262.                     i == noErr; 
  1263.                    i = PBGetCatInfoSync( &CinfoPB ) )
  1264.     {
  1265.             // if this is not a folder and we successfully create an FSSpec
  1266.         if (( ! (CinfoPB.hFileInfo.ioFlAttrib & (1<<4)) ) 
  1267.             && ( noErr == (FSMakeFSSpec( CinfoPB.hFileInfo.ioVRefNum, 
  1268.                               CinfoPB.hFileInfo.ioFlParID, //ioDirID, 
  1269.                               fileName, 
  1270.                               &theFileSpec ) ) ))
  1271.         {
  1272.             file->Specify(&theFileSpec);
  1273.             if ( file->GetPlatformType() == kCFragLibraryFileType)
  1274.             {
  1275.                 CFragConnectionID connID;
  1276.                 ODShellPlugInInstallProc installMethod;
  1277.                 OSErr err = GetInstallEntryPt( &theFileSpec,
  1278.                         &installMethod, &connID );
  1279.  
  1280.                 ODShellPlugInActionCodes action
  1281.                         = kODShellPlugInNoAction;
  1282.                 if ( !err )
  1283.                 {
  1284.                     TRY
  1285.                         err = (*installMethod)( fEV, draft, &action );
  1286.                     CATCH_ALL
  1287.                         SetErrorCode(kODNoError);
  1288.                     ENDTRY
  1289.                 }
  1290.                 // else is not a shell plugin; continue with next file
  1291.  
  1292.                 // test again; if the FindSymbol call failed we
  1293.                 // still want to close the connection
  1294.                 if ( (err != noErr) ||
  1295.                         BITTEST(action, kODShellPlugInCloseConnection) )
  1296.                     err = CloseConnection( &connID );
  1297.  
  1298.                 if ( err )
  1299.                 {
  1300.                     ODBlockMove( theFileSpec.name, fFailedPlugInName,
  1301.                             theFileSpec.name[0]+1 );
  1302.                     THROW( err );
  1303.                 }
  1304.             }
  1305.         }
  1306.         CinfoPB.hFileInfo.ioFDirIndex++;
  1307.                 
  1308.     //need to do this each time since PBGetCatInfo call returns val here
  1309.         CinfoPB.hFileInfo.ioNamePtr = (StringPtr)fileName;
  1310.         CinfoPB.hFileInfo.ioVRefNum = fldrVRefNum;
  1311.         CinfoPB.hFileInfo.ioDirID = fldrDirID;  
  1312.     }
  1313. }
  1314.  
  1315. //------------------------------------------------------------------------------
  1316. // FindShellPlugInsFolder //ccg
  1317. //------------------------------------------------------------------------------
  1318.  
  1319. static void FindShellPlugInsFolder(short *vol, long *dir )
  1320. {
  1321.     Str255    folderName;
  1322.     
  1323.     CInfoPBRec        pb;
  1324.     memset (&pb,0,sizeof(pb));
  1325.  
  1326.         //First find System Folder
  1327.     THROW_IF_ERROR( FindFolder(kOnSystemDisk, kSystemFolderType, kDontCreateFolder, 
  1328.                                 &pb.dirInfo.ioVRefNum, &pb.dirInfo.ioDrDirID) );
  1329.  
  1330.         // find Shell Plug Ins Folder path name
  1331.     ODGetString(folderName, kODEditorsFldrStrID);
  1332.     pb.dirInfo.ioNamePtr = (StringPtr)&folderName;
  1333.     pb.dirInfo.ioFDirIndex = 0;
  1334.     THROW_IF_ERROR( PBGetCatInfoSync( &pb ) );
  1335.  
  1336.     ODGetString(folderName, kODOpenDocPartsFolderStrID);
  1337.     pb.dirInfo.ioNamePtr = (StringPtr)&folderName;
  1338.     pb.dirInfo.ioFDirIndex = 0;
  1339.     THROW_IF_ERROR( PBGetCatInfoSync( &pb ) );
  1340.  
  1341.     ODGetString(folderName, kODShellPlugInFolderStrID);
  1342.     pb.dirInfo.ioNamePtr = (StringPtr)&folderName;
  1343.     pb.dirInfo.ioFDirIndex = 0;
  1344.     THROW_IF_ERROR( PBGetCatInfoSync( &pb ) );
  1345.  
  1346.     *vol = pb.dirInfo.ioVRefNum;
  1347.     *dir = pb.dirInfo.ioDrDirID;
  1348. }
  1349. //------------------------------------------------------------------------------
  1350. // FindStationeryFolder
  1351. //------------------------------------------------------------------------------
  1352. static void FindStationeryFolder(short *vol, long *dir )
  1353. {
  1354.     Str255    folderName;
  1355.     ODSLong    unused;
  1356.     
  1357.     CInfoPBRec        pb;
  1358.     memset (&pb,0,sizeof(pb));
  1359.  
  1360.         //First find Desktop Folder
  1361.     THROW_IF_ERROR( FindFolder(kOnSystemDisk, kDesktopFolderType, kCreateFolder, 
  1362.                                 vol, &unused ));
  1363.  
  1364.         // find Stationery Folder path name
  1365.     ODGetString(folderName, kODStationeryFldrStrID);
  1366.     pb.dirInfo.ioNamePtr = (StringPtr)&folderName;
  1367.     pb.dirInfo.ioDrDirID = fsRtDirID; //2;
  1368.     pb.dirInfo.ioVRefNum = *vol;
  1369.     pb.dirInfo.ioFDirIndex = 0;
  1370.     if ( PBGetCatInfoSync( &pb ) )
  1371.     {
  1372.         THROW_IF_ERROR( 
  1373.             DirCreate(*vol, fsRtDirID, folderName, dir));
  1374.     } else {    
  1375.         *dir = pb.dirInfo.ioDrDirID;
  1376.     }
  1377. }
  1378.  
  1379. //-------------------------------------------------------------------------------------
  1380. // RealShell::go
  1381. //-------------------------------------------------------------------------------------
  1382.  
  1383. void RealShell::go()
  1384. {
  1385.     ODBoolean    initialized;
  1386.     ODVolatile(initialized);
  1387.     ODULong        errorLoops = 0; // Counts the number of times in a row we caught
  1388.                                 //    an out-of-memory error in the event loop.
  1389.     ODVolatile(errorLoops);
  1390.     
  1391.     #if ODDebug
  1392.     if ( gDumpBlocksOnClose )
  1393.     {
  1394.         SetOutputMode(kWriteToFile);
  1395.         // MMBeginLeakChecking();
  1396.         // gLeakChecking = kODTrue;
  1397.         MMTrackStackCrawls( kODTrue );
  1398.     }
  1399.     #endif
  1400.     
  1401.     {
  1402.         TRY
  1403.             this->Initialize();
  1404.             initialized = kODTrue;
  1405.         CATCH_ALL
  1406.             initialized = kODFalse;
  1407.             ODShellLowMemoryGoodbye();
  1408.             // THIS CALL USES OD SERVICES THAT MAY NOT BE THERE!
  1409. //            this->ExceptionAlert(ErrorCode(),ErrorMessage());
  1410.         ENDTRY
  1411.     }
  1412.     
  1413. #ifdef SHLTestErrorDialogUsage
  1414.     SHLDebugStr("\pPreErrorDialog HeapInfo…");
  1415.     HeapInfo();
  1416.     this->ExceptionAlert(1,kODNULL);
  1417. #endif
  1418.  
  1419. #ifdef SHLTestSessionOverhead
  1420.     SHLDebugStr("\pPreExtraSession HeapInfo…");
  1421.     HeapInfo();
  1422.  
  1423.     TRY
  1424.         TempODSession aSession = new ODSession;
  1425.         THROW_IF_NULL(aSession); // som objects don't autothrow if unable to allocate.
  1426.         aSession->InitSession(fEV);
  1427.     CATCH_ALL
  1428.     ENDTRY
  1429.  
  1430.     SHLDebugStr("\pPostExtraSession HeapInfo…");
  1431.     HeapInfo();
  1432. #endif
  1433.  
  1434.     EventRecord        eventRec;
  1435.     if (initialized)
  1436.     while (!fDispatcher->ShouldExit(fEV)) 
  1437.     {
  1438.         TRY
  1439.             gODDelayBentoFatalError = gODSuppressBentoFatalError = kODFalse;
  1440.             if ( gODBentoFatalErrorHasOccurred )
  1441.                 ODBentoFatalError(/*allowSuppress*/ kODFalse);
  1442.             
  1443.             if( this->CheckFileLocation() )            // Update if document renamed/moved
  1444.                 break;                                // we may need to quit if trashed
  1445.             
  1446.             ODSLong sleep = fDispatcher->GetSleepTime(fEV);
  1447.             if( sleep > kMaxTimeBetweenLocationChecks )
  1448.                 sleep = kMaxTimeBetweenLocationChecks;
  1449.             
  1450.             WaitNextEvent (everyEvent, &eventRec, sleep, fDispatcher->GetMouseRegion(fEV));
  1451.             if( eventRec.what == osEvt && (( eventRec.message >> 24 ) & 0x00FF)==0x01 )
  1452.                 fProcessIsActive= (eventRec.message & 0x01)!=0;
  1453.  
  1454.             this->DispatchEvent((ODEventData*)&eventRec);
  1455.  
  1456.             this->CheckMenuBar();
  1457.  
  1458.             if( fProcessIsActive )
  1459.                 this->CheckFreeMemory();            // Display low-mem alert
  1460.     
  1461.             errorLoops = 0; // Reset this. We got through the loop OK.
  1462.  
  1463.         CATCH_ALL
  1464.  
  1465.             // IF WE CATCH A LOW-MEMORY ERROR HERE MORE THAN 2 TIMES IN A ROW,
  1466.             //    WE OUTTIE.
  1467.             ODError thisError = ErrorCode();
  1468.             if (thisError == kODErrOutOfMemory || thisError == memFullErr)
  1469.             {
  1470.                 ++errorLoops;
  1471.                 if (errorLoops > 2)
  1472.                     ODShellLowMemoryGoodbye();
  1473.             }
  1474.  
  1475.             this->ExceptionAlert(ErrorCode(),ErrorMessage());
  1476.  
  1477.         ENDTRY
  1478.  
  1479.     }
  1480.     
  1481.     // Check to see if we failed in the odoc or oapp appleevent handlers.
  1482.     ODError    err = this->GetAEError();
  1483.     if (err)
  1484.     {
  1485.         this->ExceptionAlert(err,kODNULL);
  1486.     }
  1487. }
  1488.  
  1489.  
  1490. //-------------------------------------------------------------------------------------
  1491. // Notification Stuff
  1492. //-------------------------------------------------------------------------------------
  1493.  
  1494. struct NotEntry :public Link {
  1495.     RealShell::Notifier n;
  1496.     ODULong                refCon;
  1497.     NMRec                nm;
  1498.     
  1499.     virtual ~NotEntry( );
  1500. };
  1501.  
  1502. NotEntry::~NotEntry( )
  1503. {
  1504.     if( nm.nmIcon ) DisposeIconSuite(nm.nmIcon,kODTrue);
  1505. }
  1506.  
  1507. static ODIconFamily
  1508. GetRootPartIconFamily( Environment*    ev, ODSession* session )
  1509. {
  1510.     static ODIconFamily sIcon = kODNULL;
  1511.     if( !sIcon ) {
  1512.         TempODWindow odWindow = session->GetWindowState(ev)->AcquireFrontRootWindow(ev);
  1513.         ODFrame* rootFrame = odWindow ? odWindow->GetRootFrame(ev) : kODNULL;
  1514.         sIcon = ODGetIconFamily(ev, rootFrame);
  1515.     }
  1516.     return sIcon;
  1517. }
  1518.  
  1519.  
  1520. //-------------------------------------------------------------------------------------
  1521. // RealShell::Notify
  1522. //-------------------------------------------------------------------------------------
  1523.  
  1524. void
  1525. RealShell::Notify( RealShell::Notifier n, ODULong refCon )
  1526. {
  1527.     if( fProcessIsActive )
  1528.         (this->*n)( refCon );                        // We're active, so call notifier right now.
  1529.         
  1530.     else {
  1531.         NotEntry *e = new NotEntry;
  1532.         e->n = n;
  1533.         e->refCon = refCon;
  1534.         fNotifiers.AddLast(e);
  1535.         
  1536.         e->nm.qType = nmType;
  1537.         e->nm.nmMark = 1;                                    // Mark process menu
  1538.         e->nm.nmIcon = GetRootPartIconFamily(fEV, fSession);    // Show root part's icon
  1539.         e->nm.nmSound = (Handle)-1L;                        // Play system beep
  1540.         e->nm.nmStr = kODNULL;
  1541.         e->nm.nmResp = kODNULL;
  1542.         OSErr err= NMInstall(&e->nm);
  1543.         WASSERT(err==noErr);
  1544.     }
  1545. }
  1546.  
  1547.  
  1548. //-------------------------------------------------------------------------------------
  1549. // RealShell::CancelNotification
  1550. //-------------------------------------------------------------------------------------
  1551.  
  1552. void
  1553. RealShell::CancelNotification( RealShell::Notifier n )
  1554. {
  1555.     // Removes all notifications pointing to this notifier proc.
  1556.     NotEntry *next;
  1557.     for( NotEntry *e = (NotEntry*)fNotifiers.First(); e; e=next ) {
  1558.         next = (NotEntry*)fNotifiers.After(*e);
  1559.         if( e->n == n ) {
  1560.             NMRemove(&e->nm);
  1561.             fNotifiers.Remove(*e);
  1562.             delete e;
  1563.         }
  1564.     }
  1565. }
  1566.  
  1567.  
  1568. //-------------------------------------------------------------------------------------
  1569. // RealShell::ShowPendingNotification
  1570. //-------------------------------------------------------------------------------------
  1571.  
  1572. void
  1573. RealShell::ShowPendingNotifications( )
  1574. {
  1575.     if( fProcessIsActive ) {
  1576.         NotEntry *e;
  1577.         while( !fNotifiers.IsEmpty() ) {
  1578.             e = (NotEntry*) fNotifiers.RemoveFirst();
  1579.             NMRemove(&e->nm);
  1580.             (this->*(e->n))( e->refCon );                        // Call notifier method
  1581.             delete e;
  1582.         }
  1583.     }
  1584. }
  1585.  
  1586.  
  1587. //-------------------------------------------------------------------------------------
  1588. // RealShell::DispatchEvent
  1589. //-------------------------------------------------------------------------------------
  1590.  
  1591. void RealShell::DispatchEvent(ODEventData* event)
  1592. {
  1593.     switch (event->what)
  1594.     {
  1595.     case kODEvtMouseDown:    
  1596.         this->DispatchMouseDownEvent(event);                
  1597.         break;
  1598.                 
  1599.     case kODEvtKeyDown:
  1600.         this->DispatchKeyDownEvent(event);                
  1601.         break;
  1602.                                     
  1603.     case kODEvtOS:
  1604.         // FOR NOW, EAT ALL ERRORS OCCURING DURING A SUSPEND.
  1605.         //    SEE WHAT TYPE OF OS EVENT IT IS
  1606.         ODUByte        typeOSEvent = (ODUByte) (event->message >> 24) & 0x00FF;
  1607.         ODBoolean    isSuspendEvent;
  1608.  
  1609.         //    IF IT'S A SUSPEND MESSAGE
  1610.         isSuspendEvent = ((typeOSEvent & suspendResumeMessage)
  1611.                             && (!(event->message & resumeFlag)));
  1612.         TRY
  1613.             fDispatcher->Dispatch(fEV,event);
  1614.             this->HandleOSEvent(event);
  1615.         CATCH_ALL
  1616.             if (isSuspendEvent)
  1617.                 WARN("Eating an error that occurred during suspend time.");
  1618.             else
  1619.                 RERAISE;
  1620.         ENDTRY
  1621.         break;
  1622.  
  1623.     case kHighLevelEvent:    
  1624.         if (!fDispatcher->Dispatch(fEV,event))
  1625.             this->HandleHighLevelEvent(event);                
  1626.         break;
  1627.         
  1628.     default:            
  1629.         fDispatcher->Dispatch(fEV,event);
  1630.         break;
  1631.     }
  1632. }
  1633.  
  1634. //-------------------------------------------------------------------------------------
  1635. // RealShell::DispatchMouseDownEvent
  1636. //-------------------------------------------------------------------------------------
  1637.  
  1638. void RealShell::DispatchMouseDownEvent(ODEventData* event)
  1639. {
  1640.     WindowPtr     theWindow = kODNULL;
  1641.     ODSShort     partCode = FindWindow(event->where, &theWindow);
  1642.     if (partCode == kODMDInMenuBar)
  1643.         this->DispatchMenuEvent(event);
  1644.     else if (!(fDispatcher->Dispatch(fEV,event)) && theWindow)
  1645.         this->HandleMouseDownInWindow(theWindow, partCode, event);
  1646. }
  1647.  
  1648. //-------------------------------------------------------------------------------------
  1649. // RealShell::DispatchMenuEvent
  1650. //-------------------------------------------------------------------------------------
  1651.  
  1652. void RealShell::DispatchMenuEvent(ODEventData* event)
  1653. {
  1654.     this->UpdateMenus();
  1655.     if (!(fDispatcher->Dispatch(fEV,event)))
  1656.         this->HandleMenuCommand(event->message, event);
  1657. }
  1658.  
  1659. //-------------------------------------------------------------------------------------
  1660. // RealShell::DispatchKeyDownEvent
  1661. //-------------------------------------------------------------------------------------
  1662. static ODBoolean EditFKeyDown( long message );
  1663. static ODBoolean EditFKeyDown( long message )
  1664. {
  1665.     if ( (message & charCodeMask) == 0x10 )
  1666.     {
  1667.         char keyCode = (message & keyCodeMask) >> 8;
  1668.         // aren't there constants for these keys anywhere?
  1669.         return (ODBoolean)(keyCode == 0x7A) || (keyCode == 0x78)
  1670.                 || (keyCode ==0x63) || (keyCode == 0x76);
  1671.     }
  1672.     return kODFalse;
  1673. }
  1674.  
  1675. void RealShell::DispatchKeyDownEvent(ODEventData* event)
  1676. {    
  1677.     ODBoolean cmdKeyDown = (event->modifiers & cmdKey) != 0;
  1678.     ODBoolean optionKeyDown = (event->modifiers & optionKey) != 0;
  1679.     if ( cmdKeyDown || EditFKeyDown(event->message) ) // || F1, f2, f3, f4 were pressed
  1680.         this->UpdateMenus();    
  1681.         // Fix #1221897
  1682.         // should also do update if function keys for Undo/Cut/Copy/Paste were pressed
  1683.  
  1684.     if ( !fDispatcher->Dispatch(fEV, event) )
  1685.     {
  1686.         if ( event->what == kODEvtMenu )
  1687.             this->HandleMenuCommand(event->message, event );
  1688.         else if ( cmdKeyDown && optionKeyDown )
  1689.         {
  1690.             // we have a command-key equivalent that didn't get recognized
  1691.             // because UI doesn't like the option key.  So we need to change
  1692.             // the character to what it would be without the option, then get
  1693.             // the equivalent menu and invoke its handler with the additional
  1694.             // information that the option key was down.
  1695.             
  1696.             // Adapted from Finder code furnished by Greg Anderson
  1697.             unsigned char key = event->message & charCodeMask;
  1698.             short mangledKeyCode = (short)((event->message & keyCodeMask) >> 8)
  1699.                     | (event->modifiers & keyCodeMask);  // raw key w/ all modifiers
  1700.             UInt32 state = 0;
  1701.             Ptr kchrCache = (Ptr)GetScriptManagerVariable(smKCHRCache);
  1702.             
  1703.             // Find out if the raw key code matches the character in event.message.
  1704.             unsigned char computedKey =        // only keep low byte
  1705.                     (unsigned char)KeyTranslate( kchrCache, mangledKeyCode,
  1706.                     &state );
  1707.                     
  1708.             if (computedKey == key)
  1709.             {
  1710.                 mangledKeyCode &= (0xFFFF - optionKey);    // mask out option bit
  1711.                 key = (unsigned char) KeyTranslate(kchrCache, mangledKeyCode, &state);
  1712.                 // only keep low byte; we'll use this new keycode w/o option.
  1713.  
  1714.                 // NOTE: I'm not changing the event, which HandleMenuCommand
  1715.                 // ignores anyway.
  1716. //                ODBoolean oldOptionValue = fOptionKeyDownOnMenuBarClick;
  1717.                 fOptionKeyDownOnMenuBarClick = kODTrue;            
  1718.                 this->HandleMenuCommand( MenuKey(key), event );
  1719. //                fOptionKeyDownOnMenuBarClick = oldOptionValue;
  1720.             }
  1721.         }
  1722.     }
  1723. }
  1724.  
  1725. //-------------------------------------------------------------------------------------
  1726. // RealShell::HandleOSEvent
  1727. //-------------------------------------------------------------------------------------
  1728.  
  1729. void RealShell::HandleOSEvent(ODEventData* event)
  1730. {
  1731.     // Is it a multifinder event?
  1732.     ODUByte typeOSEvent = (ODUByte) (event->message >> 24) & 0x00FF;
  1733.     
  1734.     // Switch on the type of OSEvent that occurred, high byte of message is event type
  1735.     switch (typeOSEvent) 
  1736.     {     
  1737.     case suspendResumeMessage:
  1738.         if( event->message & resumeFlag )
  1739.             this->ShowPendingNotifications();        // Display pending notifications
  1740.         else
  1741.             this->ExportClipboard(kODFalse);
  1742.         break;
  1743.     }
  1744. }
  1745.  
  1746. //-------------------------------------------------------------------------------------
  1747. // RealShell::ExportClipboard
  1748. //-------------------------------------------------------------------------------------
  1749.  
  1750. void RealShell::ExportClipboard(ODBoolean canAlert)
  1751. {
  1752.     ODClipboard* clipboard = fSession->GetClipboard(fEV);
  1753.  
  1754. //    TRY
  1755.         clipboard->ExportClipboard(fEV);
  1756. //    CATCH_ALL
  1757. //        if ( canAlert )
  1758. //            this->ExceptionAlert(ErrorCode(),ErrorMessage());
  1759. //    ENDTRY;
  1760. }
  1761.  
  1762. //-------------------------------------------------------------------------------------
  1763. // Debug Menu Support
  1764. //-------------------------------------------------------------------------------------
  1765.  
  1766.  
  1767. #if ODDebugMenu
  1768.  
  1769. #define SKIPOMPARSE
  1770. #ifdef SKIPOMPARSE
  1771. extern "C" {
  1772. #endif
  1773.  
  1774.     #define kDumpTmpBufSize 3000
  1775.     
  1776.     static char gFilterNewClass; 
  1777.     // gFilterNewClass is a global with a unique address passed to DumpObjProc as refCon
  1778.     
  1779.     static MMBoolean DumpObjProc(  const void *blk, size_t size, MMBoolean isObject,
  1780.                                     void *refCon )
  1781.     {
  1782.         if( isObject ) {
  1783.             MMValidateObject((ODObject*)blk);
  1784.             somPrintf("  %p %4lu  %s\r", blk,size, ((ODObject*)blk)->somGetClassName());
  1785.         }
  1786.         return true;        // Might check for cmd-period or something to abort...
  1787.     }
  1788.     
  1789.     static void DumpBlockStackCrawl(  const void *blk, size_t size, ODBoolean isObject,
  1790.                                     ODBoolean filter )
  1791.     {
  1792.         long flags = 0;
  1793.         StackCrawl*    sc = MMGetBlockStackCrawl( blk, &flags );
  1794.         if (sc)
  1795.         {
  1796.             if ( !isObject )
  1797.             {
  1798.                 somPrintf("%p %4lu:\r", blk, size);
  1799.             }
  1800.             static const char* kTooLongString = "... [too long]\n";
  1801.             char buffer[kDumpTmpBufSize + 32]; // add 32 for kTooLongString
  1802.             buffer[0] = 0;
  1803.             long    numFrames = sc->CountFrames();
  1804.             long    pos = 0;
  1805.             for (long i = 0; i < numFrames && pos < kDumpTmpBufSize; i++)
  1806.             {
  1807.                 size_t    offset;
  1808.                 char    tmpBuffer[256];
  1809.                 char    fnName[256];
  1810.                 if (sc->LookupSymbol(i, fnName, &offset))
  1811.                 {
  1812.                     sprintf(tmpBuffer, "%s+%d\n", fnName, offset);
  1813.                     long newPos = pos + strlen(tmpBuffer);
  1814.                     if ( newPos < kDumpTmpBufSize )
  1815.                         sprintf(&(buffer[pos]), "%s", tmpBuffer);
  1816.                     else
  1817.                         strcpy(&(buffer[pos]), kTooLongString);
  1818.                     
  1819.                     pos = newPos;
  1820.                 } 
  1821.             }
  1822.             if ( filter )
  1823.             {
  1824.                 if ( buffer[0] && !strstr(buffer, "NewClass") )
  1825.                     somPrintf("%s\r", buffer);
  1826.             }
  1827.             else
  1828.             {
  1829.                 if ( buffer[0] )
  1830.                     somPrintf("%s\r", buffer);
  1831.             }
  1832.         }
  1833.     }
  1834.  
  1835. #ifdef SKIPOMPARSE
  1836. }
  1837. #endif
  1838.  
  1839.  
  1840. struct TrackedBlockLink {
  1841.     TrackedBlockLink* fNext;
  1842.     const void*          fFirstBlock;
  1843.     StackCrawl*       fStack;
  1844.     unsigned long      fCount;
  1845.     unsigned long      fTotalSize;
  1846. };
  1847.  
  1848. static TrackedBlockLink* sTrackedBlockLinks;
  1849.     
  1850. extern "C" {
  1851. static MMBoolean 
  1852. FindObjsProc(  const void *blk, size_t size, MMBoolean isObject, void *refCon )
  1853. {
  1854.     long flags;
  1855.     StackCrawl* s = MMGetBlockStackCrawl(blk, &flags);
  1856.     if( s ) {
  1857.         size_t blockSize = MMBlockSize(blk);
  1858.         
  1859.         // This is a new block, check its stack crawl:
  1860.         TrackedBlockLink *l;
  1861.         for( l = sTrackedBlockLinks; l; l = l->fNext )
  1862.             if( *(l->fStack) == *s ) {
  1863.                 l->fCount++;
  1864.                 l->fTotalSize += blockSize;
  1865.                 // delete s;
  1866.                 // MMSetBlockStackCrawl(blk,kODNULL,0);
  1867.                 return kODTrue;
  1868.             }
  1869.         l = new TrackedBlockLink;
  1870.         l->fNext = sTrackedBlockLinks;
  1871.         l->fFirstBlock = blk;
  1872.         l->fTotalSize = blockSize;
  1873.         l->fStack = s;
  1874.         l->fCount = 1;
  1875.         sTrackedBlockLinks = l;
  1876.     }
  1877.     return kODTrue;
  1878. }
  1879. }
  1880.  
  1881. static void 
  1882. DumpFoundObjs()
  1883. {
  1884.     unsigned long count = 0;
  1885.     unsigned long space = 0;
  1886.     TrackedBlockLink* next;
  1887.     ODBoolean filter = isFilterKeyDown();
  1888.     
  1889.     for( TrackedBlockLink * l = sTrackedBlockLinks; l; l = next ) {
  1890.         count += l->fCount;
  1891.         next = l->fNext;
  1892.         // if( l->fCount >= 3 ) {
  1893.             somPrintf("• Occurred %lu time%s, %lu total bytes:\r", 
  1894.                 l->fCount, (l->fCount == 1)? "": "s", l->fTotalSize);
  1895.             size_t size = MMBlockSize(l->fFirstBlock);
  1896.             ODBoolean isObject = MMIsObject(l->fFirstBlock);
  1897.             
  1898.             DumpObjProc(l->fFirstBlock, size, isObject, kODNULL);
  1899.             DumpBlockStackCrawl(l->fFirstBlock, size, isObject, filter);
  1900.             
  1901.             space += l->fTotalSize + (l->fCount * 8);    // Add 8 bytes for per-block overhead
  1902.         // }
  1903.         delete l;
  1904.     }
  1905.     sTrackedBlockLinks = kODNULL;
  1906.     if( space > 0 )
  1907.         somPrintf("••• Estimated space in %lu tracked blocks: %lu bytes\r", count, space);
  1908.     else
  1909.         somPrintf("••• No tracked blocks found!\r");
  1910. }    
  1911.  
  1912. static void
  1913. DumpHeapObjects( ODBoolean objectsOnly )
  1914. {
  1915.     const char *name;
  1916.     size_t allocated, free,blocks,objects;
  1917.     MMGetHeapInfo(kDefaultHeapID,
  1918.                     &name, &allocated, &free, &blocks, &objects);
  1919.     somPrintf("••• Dump of %s •••\r%lu bytes allocated, %lu free (%.1f%% free).\r",
  1920.                     name, (ODULong)allocated, (ODULong)free, 100.0*free/(float)(allocated+free) );
  1921.     somPrintf("There are %lu blocks, of which %lu are objects:\r", (ODULong)blocks, (ODULong)objects);
  1922.  
  1923.     if ( !objectsOnly && gTrackStackCrawls )
  1924.     {
  1925.         sTrackedBlockLinks = kODNULL;
  1926.  
  1927.         MMTrackStackCrawls(kODFalse); // disable stack crawls in FindObjsProc()
  1928.         MMWalkHeap(kDefaultHeapID, &FindObjsProc, kODNULL);
  1929.         DumpFoundObjs();
  1930.         MMTrackStackCrawls(kODTrue); // re-enable stack crawls
  1931.  
  1932.         sTrackedBlockLinks = kODNULL;
  1933.     }
  1934.     else
  1935.     {
  1936.         somPrintf("  ADDRESS  SIZE  CLASS\r");
  1937.         MMWalkHeap(kDefaultHeapID, &DumpObjProc, kODNULL);
  1938.     }
  1939. }
  1940.  
  1941.  
  1942. #endif
  1943.  
  1944. //-------------------------------------------------------------------------------------
  1945. // RealShell::HandleMenuCommand
  1946. //-------------------------------------------------------------------------------------
  1947.  
  1948.  
  1949. void RealShell::HandleMenuCommand(ODSLong menuResult, ODEventData* event)
  1950. {
  1951.     ODUnused(event);
  1952.  
  1953.     ODSShort menu = HiWord(menuResult);
  1954.     ODSShort item = LoWord(menuResult);
  1955.     TempODMenuBar menuBar = fWindowState->AcquireCurrentMenuBar(fEV);
  1956.     ODCommandID command = menuBar->GetCommand(fEV,menu, item);
  1957.  
  1958.     if (menuBar->IsCommandSynthetic(fEV,command))
  1959.     {
  1960.         switch (menu)
  1961.         {
  1962.             case kODAppleMenuID: // Apple
  1963.             {
  1964.                 Str255        daName;
  1965.                 ODSShort    daRefNum;
  1966.                 
  1967.                 GetMenuItemText(GetMenuHandle(kODAppleMenuID), item, daName);
  1968.                 daRefNum = OpenDeskAcc(daName);
  1969.                 HiliteMenu(0);
  1970.                 break;
  1971.             }
  1972.  
  1973.             default:
  1974.                 break;
  1975.         }
  1976.     }
  1977.     else 
  1978.     {
  1979.         ODDraft*        activeDraft  = ODGetActiveDraft(fEV, fSession);
  1980.         ODDocument*        activeDocument;
  1981.         if (activeDraft)
  1982.             activeDocument = activeDraft->GetDocument(fEV);
  1983.         else
  1984.             activeDocument = kODNULL;
  1985.         
  1986.         switch(command)
  1987.         {
  1988.             case kODCommandAbout: {
  1989.                 CUsingLibraryResources r;
  1990.                 ODSShort itemHit;
  1991.                 GrafPtr savePort;
  1992.                 GetPort(&savePort);
  1993.                 
  1994.                 fWindowState->DeactivateFrontWindows(fEV);
  1995.                 TRY
  1996.                     DialogPtr aboutDlg = ShowAboutScreen();
  1997.                 
  1998.                     ModalDialog(kODNULL /*modalFilter*/, &itemHit);
  1999.                     if (aboutDlg)
  2000.                         DisposeDialog(aboutDlg);
  2001.                 CATCH_ALL
  2002.                     fWindowState->ActivateFrontWindows(fEV);
  2003.                     RERAISE;
  2004.                 ENDTRY
  2005.                 fWindowState->ActivateFrontWindows(fEV);
  2006.  
  2007.                 SetPort(savePort);
  2008.                 break;
  2009.             }
  2010.             
  2011. // POSSIBLE FIX NEEDED: needs to use activeDocument?
  2012.             case kODCommandNew:            delete (this->New());    break;
  2013.                     
  2014.             case kODCommandOpenDocument:    this->OpenStdFile();    break;
  2015.                 
  2016.             case kODCommandClose:
  2017.                 if (fOptionKeyDownOnMenuBarClick)
  2018.                 {
  2019.                     this->CloseDocument(activeDocument, kAEAsk);
  2020.                 } 
  2021.                 else
  2022.                 {
  2023.                     WindowPtr platformWindow = kODNULL;
  2024.                     {
  2025.                     TempODWindow window = ODAcquireActiveWindow(fEV, fSession);
  2026.                     if (window)
  2027.                         platformWindow = window->GetPlatformWindow(fEV);
  2028.                     }
  2029.                     this->CloseWindow(platformWindow, kAEAsk);
  2030.                 }
  2031.                 break;
  2032.  
  2033.             case kODCommandDeleteDocument:    this->DeleteDocument(activeDocument);    break;
  2034.             
  2035.             case kODCommandSave:            this->Save(activeDocument);                break;
  2036.                 
  2037.             case kODCommandSaveACopy:        this->SaveACopy(activeDraft);            break;
  2038.                 
  2039.             case kODCommandRevert:            this->Revert(activeDocument);            break;
  2040.                 
  2041.             case kODCommandDraft:            this->Drafts(activeDocument);            break;
  2042.                     
  2043.             case kODCommandDocumentInfo:    this->DocumentInfo(activeDocument);        break;
  2044.             
  2045. #ifdef SUPPORT_QUIT
  2046.             case kODCommandQuit:            this->CloseAllDocs(kAEAsk);                break;
  2047. #endif                    
  2048.             case kODCommandUndo:    fSession->GetUndo(fEV)->Undo(fEV);        break;
  2049.  
  2050.             case kODCommandRedo:    fSession->GetUndo(fEV)->Redo(fEV);        break;
  2051.  
  2052.             // case kODCommandGetPartInfo:        this->PartInfo();        break;
  2053.  
  2054. #if ODDebugMenu
  2055.             case kODCommandDBHeapInfo: {
  2056.                 HeapInfo();
  2057.                 break;
  2058.             }
  2059.             case kODCommandDBDumpObjects:
  2060.                 DumpHeapObjects( /*objectsOnly*/ kODTrue );
  2061.                 break;
  2062.             case kODCommandDBDumpBlocks:
  2063.                 DumpHeapObjects( /*objectsOnly*/ kODFalse );
  2064.                 break;
  2065.             case kODCommandDBMemValidation:
  2066.                 if( gMemValidation ) {
  2067.                     if( gHeapChecking ) {            // When turning off validation,
  2068.                         MMEndHeapChecking();        // turn heap checking off too
  2069.                         gHeapChecking = kODFalse;
  2070.                     }
  2071.                     MMEndMemValidation();
  2072.                     gMemValidation = kODFalse;
  2073.                 } else {
  2074.                     MMBeginMemValidation();
  2075.                     gMemValidation = kODTrue;
  2076.                 }
  2077.                 break;
  2078.             case kODCommandDBHeapChecking:
  2079.                 if( gHeapChecking ) {
  2080.                     MMEndHeapChecking();
  2081.                     gHeapChecking = kODFalse;
  2082.                 } else {
  2083.                     MMBeginMemValidation();            // When turning on heap checking,
  2084.                     gMemValidation = kODTrue;        // turn validation on too
  2085.                     MMBeginHeapChecking();
  2086.                     gHeapChecking = kODTrue;
  2087.                 }
  2088.                 break;
  2089.             case kODCommandDBLeakChecking:
  2090.                 if( gLeakChecking )
  2091.                     MMEndLeakChecking();
  2092.                 else
  2093.                     MMBeginLeakChecking();
  2094.                 gLeakChecking = !gLeakChecking;
  2095.                 gTrackStackCrawls = gLeakChecking;
  2096.                 break;
  2097.             case kODCommandDBDumpBlocksOnClose:
  2098.                 gDumpBlocksOnClose = !gDumpBlocksOnClose;
  2099.                 break;
  2100.             case kODCommandDBTrackStackCrawls:
  2101.                 if( gTrackStackCrawls )
  2102.                     MMTrackStackCrawls( kODFalse );
  2103.                 else
  2104.                     MMTrackStackCrawls( kODTrue );
  2105.                 gTrackStackCrawls = !gTrackStackCrawls;
  2106.                 break;
  2107.             case kODCommandDBEatMemory:
  2108.                 (void) NewHandle(32*1024);            // For testing low-mem survival!
  2109.                 if( MemError() ) {
  2110.                     SysBeep(3);
  2111.                     WARN("Error %d eating memory!;ht",MemError());
  2112.                 }
  2113.                 break;
  2114.             case kODCommandDBPurge:
  2115.                 this->Purge(10*1024*1024);
  2116.                 break;
  2117.             case kODCommandDBLogStdout:
  2118.                 if( GetOutputMode() != kWriteToFile )
  2119.                     SetOutputMode(kWriteToFile);
  2120.                 else
  2121.                     SetOutputMode(kNoOutput);
  2122.                 break;
  2123.             case kODCommandDBLogDebugWindow:
  2124.                 if( GetOutputMode() != kWriteToDebugWindow )
  2125.                     SetOutputMode(kWriteToDebugWindow);
  2126.                 else
  2127.                     SetOutputMode(kNoOutput);
  2128.                 break;
  2129.             case kODCommandDBLogDebugStr:
  2130.                 if( GetOutputMode() != kGenerateDebugStrs )
  2131.                     SetOutputMode(kGenerateDebugStrs);
  2132.                 else
  2133.                     SetOutputMode(kNoOutput);
  2134.                 break;
  2135.             case kODCommandDBBreakOnThrow:
  2136.                 BreakOnThrow( ! BreakOnThrow(kODFalse) );
  2137.                 // This looks weird, but we have to call it once to get the
  2138.                 // old value, then again to set it to the opposite of that.
  2139.                 break;
  2140.             case kODCommandDBSOMTrace:
  2141.                 SOM_TraceLevel = !SOM_TraceLevel;
  2142.                 break;
  2143. #endif
  2144.  
  2145.             default:
  2146.                 // some part enabled a menu command but did not handle it
  2147.                 break;
  2148.         }
  2149.         HiliteMenu(0);
  2150.     } 
  2151. }
  2152.  
  2153. //-------------------------------------------------------------------------------------
  2154. // RealShell::HandleMouseDownInWindow
  2155. //-------------------------------------------------------------------------------------
  2156.  
  2157. void RealShell::HandleMouseDownInWindow(WindowPtr pwindow, ODSShort partCode, ODEventData* event)
  2158. {
  2159.     switch (partCode)
  2160.     {
  2161.     case kODMDInGoAway:    
  2162.         this->HandleMouseDownInCloseBox(pwindow, event);            
  2163.         break;
  2164.  
  2165.     case kODMDInDrag:        
  2166.         this->HandleMouseDownInDragRegion(pwindow, event);            
  2167.         break;
  2168.         
  2169.     case kODMDInGrow:        
  2170.         this->HandleMouseDownInGrowBox(pwindow, event);            
  2171.         break;
  2172.                         
  2173.     case kODMDInZoomIn:
  2174.     case kODMDInZoomOut:    
  2175.         this->HandleMouseDownInZoomBox(pwindow, partCode,event);    
  2176.         break;
  2177.         
  2178.     case kODMDInContent:
  2179.         {
  2180.         // This section used to select windows.
  2181.         // Parts must be responsible for window selection so that
  2182.         // the modal focus is respected.
  2183.         // Also, according to recipes, window selection should only
  2184.         // occur on mouse-up, anyway.
  2185.         TempODWindow window = fWindowState->AcquireODWindow(fEV,pwindow);
  2186.         if ( window != kODNULL )
  2187.         {
  2188.             if ( !window->IsActive( fEV ))
  2189.             {
  2190.                 SysBeep( 2 );
  2191.             }
  2192.             //window->Select(fEV);
  2193.         }
  2194.         else if ( ((WindowPeek)pwindow)->hilited == kODFalse )
  2195.         {
  2196.             WARN("This window is not registered with OpenDoc!");
  2197.             SysBeep( 2 );
  2198.             //SelectWindow(pwindow);
  2199.         }
  2200.         }
  2201.         break;
  2202.     default:                
  2203.         break;
  2204.     }
  2205. }
  2206.  
  2207. //-------------------------------------------------------------------------------------
  2208. // RealShell::HandleMouseDownInCloseBox
  2209. //-------------------------------------------------------------------------------------
  2210.  
  2211. void RealShell::HandleMouseDownInCloseBox(WindowPtr pwindow, ODEventData* event)
  2212. {
  2213.     if (TrackGoAway (pwindow, event->where))
  2214.     {
  2215.         if (IsOptionKeyDown())
  2216.         {    
  2217.             ODDocument* document = kODNULL;
  2218.             {
  2219.             TempODWindow     window = fWindowState->AcquireODWindow(fEV, pwindow);
  2220.             WASSERT(window != kODNULL);
  2221.             document = ODGetDraftOfWindow(fEV, window)->GetDocument(fEV);
  2222.             }
  2223.             this->CloseDocument(document, kAEAsk);
  2224.         }
  2225.         else
  2226.             this->CloseWindow(pwindow, kAEAsk);
  2227.     }
  2228. }
  2229.  
  2230. //-------------------------------------------------------------------------------------
  2231. // RealShell::HandleMouseDownInDragRegion
  2232. //-------------------------------------------------------------------------------------
  2233.  
  2234. void RealShell::HandleMouseDownInDragRegion(WindowPtr platformWindow, ODEventData* event)
  2235. {
  2236.     TempODWindow     window = fWindowState->AcquireODWindow(fEV,platformWindow);
  2237.     if (window != kODNULL) 
  2238.     {
  2239.         if ( window->IsActive( fEV ) || !this->IsSessionModal())
  2240.             window->Drag(fEV, &event->where, (Rect*)&ODQDGlobals.screenBits.bounds);
  2241.         else
  2242.             SysBeep( 2 );
  2243.     }
  2244.     else 
  2245.     {
  2246.         if ( ((WindowPeek)platformWindow)->hilited || !this->IsSessionModal())
  2247.         {
  2248.             WARN("Dragging non-ODWindow.");
  2249.             DragWindow(platformWindow, event->where, &(ODQDGlobals.screenBits.bounds));
  2250.         }
  2251.         else
  2252.             SysBeep( 2 );
  2253.     }
  2254.  
  2255. }
  2256.  
  2257. //-------------------------------------------------------------------------------------
  2258. // RealShell::HandleMouseDownInGrowBox
  2259. //-------------------------------------------------------------------------------------
  2260.  
  2261. void RealShell::HandleMouseDownInGrowBox(WindowPtr pwindow, ODEventData* event)
  2262. {
  2263.     if (!fWindowState->IsODWindow(fEV,pwindow))
  2264.         return;
  2265.     
  2266.     TempODWindow window = fWindowState->AcquireODWindow(fEV,pwindow);
  2267.  
  2268.     if (window == kODNULL)
  2269.         return;
  2270.         
  2271.     if (window->IsResizable(fEV))
  2272.     {
  2273.         Rect growLimits; //  = ODQDGlobals.screenBits.bounds);
  2274.         
  2275.         ODRgnHandle contRgn = 
  2276.             ((WindowRecord*)(window->GetPlatformWindow(fEV)))->contRgn;
  2277.         Rect currentBounds = (**contRgn).rgnBBox;
  2278.  
  2279.         window->GetWindowBounds(fEV, ¤tBounds);
  2280.         
  2281.         growLimits.left = currentBounds.right-currentBounds.left;
  2282.         if (growLimits.left > kMinWindowWidth)
  2283.             growLimits.left = kMinWindowWidth;
  2284.         growLimits.top = currentBounds.bottom-currentBounds.top;
  2285.         if (growLimits.top > kMinWindowHeight)
  2286.             growLimits.top = kMinWindowHeight;
  2287.             
  2288.         growLimits.right = kMaxWindowWidth;
  2289.         growLimits.bottom = kMaxWindowHeight;
  2290.         
  2291.         ODSLong newWindowSize = GrowWindow(pwindow, event->where, &growLimits);
  2292.         SizeWindow(pwindow, LoWord(newWindowSize), HiWord(newWindowSize), true);
  2293.     
  2294.         window->AdjustWindowShape(fEV);
  2295.     
  2296.         Rect r = pwindow->portRect;
  2297.         r.left = r.right  - 15;
  2298.         r.top  = r.bottom - 15;
  2299.         RgnHandle    oldClip = nil;
  2300.         GetClip(oldClip = ODNewRgn());
  2301.         ClipRect(&r);
  2302.         DrawGrowIcon(pwindow);
  2303.         SetClip(oldClip);
  2304.         ODDisposeHandle((Handle)oldClip);
  2305.     }
  2306. }
  2307.  
  2308. //-------------------------------------------------------------------------------------
  2309. // RealShell::HandleMouseDownInZoomBox
  2310. //-------------------------------------------------------------------------------------
  2311.  
  2312. void RealShell::HandleMouseDownInZoomBox(WindowPtr pwindow, ODSShort partcode, ODEventData* event)
  2313. {
  2314.     if (TrackBox(pwindow, event->where, partcode))
  2315.     {
  2316.         TempODWindow  window = kODNULL;
  2317.         
  2318.         if (fWindowState->IsODWindow(fEV,pwindow))
  2319.             window = fWindowState->AcquireODWindow(fEV,pwindow);
  2320.         
  2321.         GrafPtr port;
  2322.         GetPort(&port);
  2323.         SetPort(pwindow);
  2324.         
  2325.         ZoomWindow(pwindow, partcode, kODFalse);
  2326.         
  2327.         SetPort(port);
  2328.         
  2329.         if (window)
  2330.             window->AdjustWindowShape(fEV);
  2331.     }
  2332. }
  2333.  
  2334. //-------------------------------------------------------------------------------------
  2335. // RealShell::IsSessionModal
  2336. //-------------------------------------------------------------------------------------
  2337.  
  2338. ODBoolean RealShell::IsSessionModal()
  2339. {
  2340.     TempODFrame modalFocus = fArbitrator->AcquireFocusOwner( fEV, fModalFocusToken );    
  2341.     return modalFocus != kODNULL;
  2342. }
  2343.  
  2344. //-------------------------------------------------------------------------------------
  2345. // RealShell::UpdateMenus
  2346. //-------------------------------------------------------------------------------------
  2347.  
  2348. void RealShell::UpdateMenus()
  2349. {
  2350.     ODIText*        menuItem;
  2351.     TempODMenuBar    menuBar = fWindowState->AcquireCurrentMenuBar(fEV);
  2352.     MenuHandle        appleMenu = menuBar->GetMenu(fEV, kODAppleMenuID);
  2353.     MenuHandle        editMenu = menuBar->GetMenu(fEV, kODEditMenuID);
  2354.     ODDocument*        activeDocument = ODGetActiveDocument(fEV, fSession);
  2355.  
  2356.     fOptionKeyDownOnMenuBarClick = IsOptionKeyDown();
  2357.     
  2358. // Menu items which require resources:
  2359.     { CUsingLibraryResources r;
  2360.     
  2361.     // About Menu item
  2362.         this->RestoreMenuItem(appleMenu, kSHLMenuAbout, &fDefaultAboutMenuItem);
  2363.  
  2364.     //== Document-wide menu items
  2365.         Str255 targetName;
  2366.         if (activeDocument)
  2367.         {
  2368.             TempPlatformFile    file = 
  2369.                 GetPlatformFileFromContainer(fEV, activeDocument->GetContainer(fEV));                            
  2370.     
  2371.             file->GetAsciiName( (char*)targetName, sizeof(targetName) );
  2372.             CToPascalString((char*)targetName);
  2373.         }
  2374.         else
  2375.         {
  2376.             targetName[0] = 0;
  2377.         }
  2378.         Str255 destString;
  2379.         
  2380.     // Delete Menu item
  2381.         ReplaceIntoString( kSHLDeleteItemTemplateStrID, targetName, kODNULL,
  2382.                 destString );
  2383.         menuItem = CreateDefaultIText(destString);
  2384.         menuBar->SetItemString(fEV, kODCommandDeleteDocument, menuItem);
  2385.         DisposeIText(menuItem);
  2386.  
  2387.     // Save Menu item
  2388.         ReplaceIntoString( kSHLSaveItemTemplateStrID, targetName, kODNULL,
  2389.                 destString );
  2390.         menuItem = CreateDefaultIText(destString);
  2391.         menuBar->SetItemString(fEV, kODCommandSave, menuItem);
  2392.         DisposeIText(menuItem);
  2393.  
  2394.     // Close Menu item
  2395.         if ( !IsOptionKeyDown() )        // close the whole document
  2396.         {
  2397.             TempODWindow window = ODAcquireActiveWindow(fEV, fSession);
  2398.             ODPlatformWindow pwin = window ?
  2399.                     window->GetPlatformWindow(fEV) : kODNULL;
  2400.             if ( pwin )
  2401.                 GetWTitle( pwin, targetName );
  2402.             else
  2403.                 targetName[0] = '\0';
  2404.         }
  2405.  
  2406.         ReplaceIntoString( kSHLCloseItemTemplateStrID, targetName, kODNULL,
  2407.                 destString );
  2408.         menuItem = CreateDefaultIText(destString);
  2409.         menuBar->SetItemString(fEV, kODCommandClose, menuItem);
  2410.         DisposeIText(menuItem);
  2411.  
  2412.     // Part Info menu item
  2413.         menuItem = GetODITextInd(kSHLStrsID, kSHLStrIndMPartInfo);
  2414.         menuBar->SetItemString(fEV, kODCommandGetPartInfo, menuItem);
  2415.         DisposeIText(menuItem);
  2416.         }
  2417.     menuBar->EnableCommand(fEV, kODCommandAbout, kODTrue);
  2418.     menuBar->EnableCommand(fEV, kODCommandClose, kODTrue);
  2419.     menuBar->EnableCommand(fEV, kODCommandGetPartInfo, kODFalse);
  2420.     
  2421. // Document Menu
  2422.  
  2423.     menuBar->EnableCommand(fEV, kODCommandNew, kODTrue);
  2424.     menuBar->EnableCommand(fEV, kODCommandOpen, kODFalse);
  2425.     menuBar->EnableCommand(fEV, kODCommandOpenDocument, kODTrue);
  2426.     menuBar->EnableCommand(fEV, kODCommandInsert, kODFalse);            
  2427.     menuBar->EnableCommand(fEV, kODCommandDeleteDocument, 
  2428.             ODDocumentHasWriteAccess(fEV, fSession, activeDocument));            
  2429.  
  2430.     ODBoolean unsavedChanges = ODDocumentHasChanges(fEV, fSession, activeDocument);
  2431.     menuBar->EnableCommand(fEV, kODCommandSave, unsavedChanges);
  2432.     menuBar->EnableCommand(fEV, kODCommandSaveACopy, kODTrue);
  2433.     menuBar->EnableCommand(fEV, kODCommandRevert, unsavedChanges);
  2434.  
  2435.     menuBar->EnableCommand(fEV, kODCommandDraft,  kODTrue);
  2436.     menuBar->EnableCommand(fEV, kODCommandDocumentInfo, kODTrue);
  2437.     menuBar->EnableCommand(fEV, kODCommandPageSetup, kODFalse);
  2438.     menuBar->EnableCommand(fEV, kODCommandPrint, kODFalse);
  2439.  
  2440. #ifdef SUPPORT_QUIT
  2441.     if( fAPPLProcess )
  2442.         menuBar->EnableCommand(fEV, kODCommandQuit, kODTrue);
  2443. #endif
  2444.  
  2445. // Edit Menu
  2446.  
  2447.     this->UpdateUndoMenus();
  2448.  
  2449.     menuBar->EnableCommand(fEV, kODCommandCut, kODFalse);
  2450.     menuBar->EnableCommand(fEV, kODCommandCopy, kODFalse);
  2451.     menuBar->EnableCommand(fEV, kODCommandPaste, kODFalse);
  2452.     menuBar->EnableCommand(fEV, kODCommandPasteAs, kODFalse);
  2453.     menuBar->EnableCommand(fEV, kODCommandClear, kODFalse);
  2454.     menuBar->EnableCommand(fEV, kODCommandSelectAll, kODFalse);
  2455.  
  2456.     menuBar->EnableCommand(fEV, kODCommandPreferences , kODFalse);
  2457.     menuBar->EnableCommand(fEV, kODCommandViewAsWin, kODFalse);
  2458.  
  2459.     if ( editMenu )
  2460.         this->RestoreMenuItem(editMenu, kSHLMenuPreferences, &fDefaultPrefsMenuItem);
  2461.  
  2462. #if ODDebugMenu
  2463.     DebugOutputMode outMode = GetOutputMode();
  2464.     ODBoolean breakingOnThrow = BreakOnThrow(kODFalse);
  2465.     BreakOnThrow(breakingOnThrow);    // Have to reset original value...
  2466.     menuBar->EnableCommand(fEV, kODCommandDBDumpObjects,    outMode!=kNoOutput);
  2467.     menuBar->EnableCommand(fEV, kODCommandDBDumpBlocks,    gTrackStackCrawls>0 && outMode!=kNoOutput);
  2468.     menuBar->CheckCommand(fEV, kODCommandDBMemValidation,    gMemValidation>0);
  2469.     menuBar->CheckCommand(fEV, kODCommandDBHeapChecking,    gHeapChecking>0);
  2470.     menuBar->EnableCommand(fEV, kODCommandDBLeakChecking,    outMode!=kNoOutput);
  2471.     menuBar->CheckCommand(fEV, kODCommandDBLeakChecking,    gLeakChecking>0);
  2472.     menuBar->EnableCommand(fEV, kODCommandDBDumpBlocksOnClose,    outMode!=kNoOutput);
  2473.     menuBar->CheckCommand(fEV, kODCommandDBDumpBlocksOnClose,    gDumpBlocksOnClose>0);
  2474.     menuBar->EnableCommand(fEV, kODCommandDBTrackStackCrawls,    kODTrue);
  2475.     menuBar->CheckCommand(fEV, kODCommandDBTrackStackCrawls,    gTrackStackCrawls>0);
  2476.     menuBar->CheckCommand(fEV, kODCommandDBLogStdout,        outMode==kWriteToFile);
  2477.     menuBar->CheckCommand(fEV, kODCommandDBLogDebugWindow,    outMode==kWriteToDebugWindow);
  2478.     menuBar->CheckCommand(fEV, kODCommandDBLogDebugStr,    outMode==kGenerateDebugStrs);
  2479.     menuBar->CheckCommand(fEV, kODCommandDBBreakOnThrow,    breakingOnThrow);
  2480.     menuBar->CheckCommand(fEV, kODCommandDBSOMTrace,        SOM_TraceLevel!=0);
  2481. #endif
  2482.  
  2483.     // Let the parts have the last crack at the menus.
  2484.     fWindowState->AdjustPartMenus(fEV);
  2485. }
  2486.  
  2487. //------------------------------------------------------------------------------
  2488. // RealShell::CheckMenuBar
  2489. //------------------------------------------------------------------------------
  2490.  
  2491. void RealShell::CheckMenuBar()
  2492. {
  2493.     ODBoolean shellHadMenuFocus = fShellHasMenuFocus;
  2494.     ODTypeToken menuFocus = fSession->Tokenize(fEV, kODMenuFocus);
  2495.     TempODFrame focusFrame = fSession->GetArbitrator(fEV)->AcquireFocusOwner(fEV, menuFocus);
  2496.     fShellHasMenuFocus = (focusFrame == kODNULL);
  2497.  
  2498.     if (fShellHasMenuFocus && !shellHadMenuFocus)
  2499.     {
  2500.         TempODMenuBar baseMenuBar = fWindowState->AcquireBaseMenuBar(fEV);
  2501.         if (baseMenuBar)
  2502.             baseMenuBar->Display(fEV);
  2503.     }
  2504. }
  2505.     
  2506. //------------------------------------------------------------------------------
  2507. // RealShell::UpdateUndoMenus
  2508. //------------------------------------------------------------------------------
  2509.  
  2510. void RealShell::UpdateUndoMenus()
  2511. {
  2512.     ODUndo*            undo = fSession->GetUndo(fEV);
  2513.     ODPart*            part;
  2514.     ODActionData    actionData;
  2515.     ODActionType    actionType;
  2516.     ODName            actionLabel;
  2517.  
  2518.     ODVolatile(actionLabel);
  2519.     ODVolatile(actionData);
  2520.  
  2521.     actionLabel.text._buffer = kODNULL;
  2522.     actionData._buffer = kODNULL;
  2523.  
  2524.     TRY
  2525.         TempODMenuBar    menuBar = fWindowState->AcquireCurrentMenuBar(fEV);
  2526.         MenuHandle        editMenu = menuBar->GetMenu(fEV, kODEditMenuID);
  2527.  
  2528.         // these IsCommandRegistered calls are to prevent ResetUndoText from
  2529.         // being called with a null menu, which is what you get at least
  2530.         // in the EditorSetup case.  Other cases might not be detected
  2531.  
  2532.         if (undo->PeekUndoHistory(fEV, &part, &actionData, &actionType,
  2533.                                     &actionLabel))
  2534.         {
  2535.             menuBar->EnableCommand(fEV, kODCommandUndo, kODTrue);
  2536.             menuBar->SetItemString(fEV, kODCommandUndo, &actionLabel);
  2537.         }
  2538.         else
  2539.         {
  2540.             menuBar->EnableCommand(fEV, kODCommandUndo, kODFalse);
  2541.             this->ResetUndoText(editMenu);
  2542.         }
  2543.     
  2544.         DisposeITextStruct(actionLabel);
  2545.         DisposeByteArrayStruct(actionData);
  2546.         actionLabel.text._buffer = kODNULL;
  2547.         actionData._buffer = kODNULL;
  2548.  
  2549.         if (undo->PeekRedoHistory(fEV, &part, &actionData, &actionType,
  2550.                                     &actionLabel))
  2551.         {
  2552.             menuBar->EnableCommand(fEV, kODCommandRedo, kODTrue);
  2553.             menuBar->SetItemString(fEV, kODCommandRedo, &actionLabel);
  2554.         }
  2555.         else
  2556.         {
  2557.             menuBar->EnableCommand(fEV, kODCommandRedo, kODFalse);
  2558.             this->ResetRedoText(editMenu);
  2559.         }
  2560.     CATCH_ALL
  2561.         if (actionLabel.text._buffer)
  2562.             DisposeITextStruct(actionLabel);
  2563.         if (actionData._buffer)
  2564.             DisposeByteArrayStruct(actionData);
  2565.         RERAISE;
  2566.     ENDTRY
  2567.  
  2568.     DisposeITextStruct(actionLabel);
  2569.     DisposeByteArrayStruct(actionData);
  2570. }
  2571.  
  2572.  
  2573. //-------------------------------------------------------------------------------------
  2574. // RealShell::ResetUndoText
  2575. //-------------------------------------------------------------------------------------
  2576.  
  2577. void RealShell::ResetUndoText(MenuHandle editMenu)
  2578. {
  2579.     if ( editMenu )
  2580.         this->RestoreMenuItem(editMenu, kSHLMenuUndo, &fDefaultUndoMenuItem);
  2581. }
  2582.  
  2583. //-------------------------------------------------------------------------------------
  2584. // RealShell::ResetRedoText
  2585. //-------------------------------------------------------------------------------------
  2586.  
  2587. void RealShell::ResetRedoText(MenuHandle editMenu)
  2588. {
  2589.     if ( editMenu )
  2590.         this->RestoreMenuItem(editMenu, kSHLMenuRedo, &fDefaultRedoMenuItem);
  2591. }
  2592.  
  2593. //-------------------------------------------------------------------------------------
  2594. // New
  2595. //-------------------------------------------------------------------------------------
  2596.  
  2597. PlatformFile*    RealShell::New()
  2598. {
  2599.     // create another container, create a root part of the same kind and editor
  2600.     // as the root part of the active window
  2601.  
  2602.     TempODType         rootPartType    = kODNULL;
  2603.     TempODEditor    editor            = kODNULL;
  2604.     TempODName        category        = kODNULL;
  2605.     ODStorageUnit*    psu                = kODNULL;
  2606.     PlatformFile*     newFile            = new PlatformFile();
  2607.  
  2608.     TempODWindow    window = ODAcquireActiveWindow(fEV, fSession);
  2609.     if (window)
  2610.     {
  2611.         TempODPart part = window->GetRootFrame(fEV)->AcquirePart(fEV);
  2612.         ASSERT((ODPart*)part != kODNULL, kODErrNoDraftProperties);  
  2613.             // !!!!! Should probably have its own errorcode, even though the user
  2614.             // error message will be the same.
  2615.         category = ODGetCategory(fEV, part, fSession->GetNameSpaceManager(fEV));    
  2616.         psu = part->GetStorageUnit(fEV);
  2617.     }
  2618.     
  2619.     if (psu &&
  2620.         psu->Exists(fEV, kODPropContents, (ODValueType)kODNULL, (ODValueIndex)kODNULL)) 
  2621.     {
  2622.         psu->Focus(fEV, kODPropContents, kODPosSame, (ODValueType)kODNULL,1, kODPosFirstSib);
  2623.         rootPartType = psu->GetType(fEV);
  2624.         editor = (ODEditor)ODGetISOStrProp(fEV, psu, kODPropPreferredEditor, kODEditor, kODNULL, kODNULL);
  2625.  
  2626.         TempPlatformFile    file = GetPlatformFileFromContainer(fEV,
  2627.                                     psu->GetDraft(fEV)->GetDocument(fEV)->GetContainer(fEV));
  2628.         newFile->SpecifyFromFile(file);
  2629.     }
  2630.  
  2631.     {
  2632.     ODContainer*    container;
  2633.     CreateUntitledContainer(kODNULL, &container, newFile, category);
  2634.     TempODContainer newContainer = container;
  2635.     ODNewDocument(fEV, newContainer, rootPartType, editor);    
  2636.     }
  2637.     
  2638.     if( fAPPLProcess )
  2639.         this->OpenFile(newFile);
  2640.     else
  2641.         this->OpenAnotherFile(newFile, kODNULL, kODTrue, kODTrue);        // Both are true because this is a new unsaved doc
  2642.     return newFile;
  2643. }
  2644.  
  2645. //-------------------------------------------------------------------------------------
  2646. // New File(Name/Spec)
  2647. //-------------------------------------------------------------------------------------
  2648.  
  2649. ODStatic void    CreateNewUntitledFile(PlatformFile* newFile, 
  2650.                         char* fileNameSeed)
  2651. {
  2652.     Str255        fileName; // !!!! MUST BE AN ARRAY IN ORDER TO WORK (sizeof used below)
  2653.         
  2654.     if (newFile->IsStationery())
  2655.     {
  2656.         newFile->GetAsciiName((char*)fileName, sizeof(fileName)-1);
  2657.     }
  2658.     else if (fileNameSeed != kODNULL)
  2659.     {
  2660.         strncpy((char*)fileName, fileNameSeed, sizeof(fileName)-1);
  2661.     }
  2662.     else
  2663.     {
  2664.         strcpy((char*)fileName, "");
  2665.     }
  2666.     
  2667.     CToPascalString((char*)fileName);
  2668.     if ( fileName[0] > kODMaxFileNameSize )
  2669.         (void)ClipStringToBytes( fileName, kODMaxFileNameSize, smSystemScript );
  2670.     PascalToCString(fileName);
  2671.     
  2672.     newFile->SetAsciiName((char*)fileName);
  2673.     
  2674.     CreateNewFile(newFile, kODForceNewName);
  2675. }
  2676.  
  2677. void    CreateNewFile(PlatformFile* newFile, ODBoolean forceNewName)
  2678. {
  2679.     ODSLong        seed = 0;
  2680.     ODULong        err = noErr;
  2681.  
  2682.     ODSByte         prefixName[kODMaxFileNameSize+1];
  2683.     newFile->GetAsciiName(prefixName, kODMaxFileNameSize);
  2684.     prefixName[kODMaxFileNameSize] = 0;
  2685.     ODUShort    prefixLen = strlen(prefixName);
  2686.  
  2687.     ODSByte         newName[kODMaxFileNameSize+1];
  2688.     strcpy(newName,prefixName);
  2689.     
  2690.     ODFileSpec fs = newFile->GetFileSpec();
  2691.  
  2692.     while (GetVolumeWritableSpace(&fs, kODNULL) < kSpaceNeededForNewDocument)
  2693.     {
  2694.         
  2695.         THROW_IF_ERROR(FindFolder(kOnSystemDisk, kDesktopFolderType, kCreateFolder,
  2696.                                 &(fs.vRefNum), &(fs.parID)));
  2697.         
  2698.         if (GetVolumeWritableSpace(&fs, &err) >= kSpaceNeededForNewDocument)
  2699.               break;
  2700.  
  2701.         THROW_IF_ERROR(err);
  2702.         THROW(kODErrSystemVolumeIsFull);
  2703.  
  2704.     // It would be nice to try other volumes as well, like:
  2705.     //   iterate through local non-removable volumes
  2706.     //     if enough space on one of those, then use it & break; break;
  2707.     //   iterate through local removable volumes
  2708.     //     if enough space on one of those, then use it & break; break;
  2709.     //   iterate through remote volumes
  2710.     //     if enough space on one of those, then use it & break; break;
  2711.     
  2712.     //  THROW(kODErrAllWritableVolumesAreFull);
  2713.  
  2714.     }
  2715.     newFile->Specify(&fs);
  2716.     newFile->UniquifyName( kODNoResourceID /*kConcatDefaultNameNoNumStrID*/, kODNULL,
  2717.             kSHLNewFilenameTemplateStrID, kODNULL, 1, kSpecifyNewNameOnly, forceNewName );
  2718.     
  2719. }    // CreateNewFile
  2720.  
  2721. void    RealShell::CreateUntitledContainer(ODDocument** documentPtr,
  2722.             ODContainer** containerPtr, PlatformFile* newFile, ODName* fileNameSeed)
  2723. {
  2724.     char* cfnSeed = kODNULL;
  2725.     if (fileNameSeed != kODNULL)
  2726.         cfnSeed = GetITextCString(fileNameSeed, kODNULL);
  2727.         
  2728.     CreateNewUntitledFile(newFile, cfnSeed);
  2729.  
  2730.     ODDeleteObject(cfnSeed);
  2731.     
  2732.     newFile->Create(kODShellSignature, kODShellSignature, 0);
  2733.  
  2734.     ODULong refNumCount;
  2735.     ODSShort* refNums;
  2736.     if (documentPtr)
  2737.     {
  2738.         GetLocalPaths(&(newFile->GetFileSpec()), kDataFork,
  2739.                           &refNumCount, &refNums);
  2740.     }
  2741.  
  2742.     (*containerPtr) = CreateFileContainer(fEV, fSession, &(newFile->GetFileSpec()));
  2743.  
  2744.     if (documentPtr)
  2745.     {
  2746.         *documentPtr = (*containerPtr)->AcquireDocument(fEV, kODDefaultDocument);    // -- TÇ: documentPtr acquires a document
  2747.     }
  2748. }
  2749.  
  2750. void    RealShell::CreateTitledContainer(ODDocument** documentPtr,
  2751.             ODContainer** containerPtr, PlatformFile* newFile, char* newName)
  2752. {
  2753.     newFile->SetAsciiName(newName);
  2754.     
  2755.     CreateNewFile(newFile, kODTryCurrentName);
  2756.     
  2757.     newFile->Create(kODShellSignature, kODShellSignature, 0);
  2758.  
  2759.     ODULong refNumCount;
  2760.     ODSShort* refNums;
  2761.     if (documentPtr)
  2762.     {
  2763.         GetLocalPaths(&(newFile->GetFileSpec()), kDataFork,
  2764.                           &refNumCount, &refNums);
  2765.     }
  2766.     
  2767.     (*containerPtr) = CreateFileContainer(fEV, fSession, &(newFile->GetFileSpec()));
  2768.         
  2769.     if (documentPtr)
  2770.     {
  2771.         *documentPtr = (*containerPtr)->AcquireDocument(fEV, kODDefaultDocument);    // -- TÇ: documentPtr acquires a document
  2772.     }
  2773. }
  2774.  
  2775. //------------------------------------------------------------------------------
  2776. // Temporary File(Name/Spec)
  2777. //------------------------------------------------------------------------------
  2778.  
  2779. void    CreateTempName(short seed, Str255 name, ODBoolean isFile)
  2780. {
  2781.     // Don't modify this one!
  2782.     char* nmSeed = isFile? "ODShellTempFile" : "ODShellTempFolder";
  2783.     strcpy((char*)name, nmSeed);
  2784.  
  2785.     char theNum[10];
  2786.     NumToString(seed, (StringPtr)theNum); 
  2787.     WASSERT(theNum[0] <= 5);
  2788.     p2cstr((StringPtr)theNum);
  2789.  
  2790.     strcat((char*)name, theNum);
  2791.     c2pstr((char *)name);
  2792. }
  2793.  
  2794.  
  2795. void RealShell::CreateUniqueTmpFolderForFile(ODFileSpec* result,
  2796.         Str63 fileName)
  2797. {
  2798.     Str255        myName;
  2799.     ODSLong    myDirID;
  2800.     ODSShort    myVRef;
  2801.     GetTempFolder(&myVRef, &myDirID);
  2802.  
  2803.     OSErr err;
  2804.     short limit = kMaxUniqueNameTries;
  2805.     while ( --limit )
  2806.     {
  2807.         CreateTempName( fUniqueNameSeed++, myName, kODFalse );
  2808.         long createdDirID;
  2809.         err = DirCreate( myVRef, myDirID, myName,
  2810.                 &createdDirID );
  2811.         if ( err == noErr )
  2812.         {
  2813.             FSMakeFSSpec(myVRef, createdDirID, fileName, result);
  2814.             return;
  2815.         }
  2816.     }
  2817.     THROW( err );
  2818. }
  2819.  
  2820. void    GetTempFolder(ODSShort* VRef,ODSLong* DirID)
  2821. {
  2822.     FindFolder(0, kTemporaryFolderType, kCreateFolder,VRef,DirID);
  2823. }
  2824.  
  2825. //-------------------------------------------------------------------------------------
  2826. // CopyResources -- copy the document resources from one file to another
  2827. //-------------------------------------------------------------------------------------
  2828.  
  2829. ODStatic void    CopyResources(PlatformFile* srcFile, PlatformFile* dstFile)
  2830. {
  2831.     CUsingLibraryResources r;
  2832.     VerifyDocumentStub(&(dstFile->GetFileSpec()), kODNULL);
  2833.     // Makes sure to copy resources into the new document.
  2834.     
  2835.     ODULong sizeOfResource;
  2836.     for(ODUShort i=0; i<= 1; i++) {
  2837.         ODPtr sizeRes = srcFile->ReadResourcePtr(kSIZERsrcType, i, &sizeOfResource);
  2838.         if (sizeRes != kODNULL) {
  2839.             dstFile->WriteResourcePtr(kSIZERsrcType, i, sizeRes, sizeOfResource);
  2840.             ODDisposePtr(sizeRes);
  2841.         }
  2842.     }    
  2843. }
  2844.  
  2845. //-------------------------------------------------------------------------------------
  2846. // Open
  2847. //-------------------------------------------------------------------------------------
  2848.  
  2849. ODDocument*
  2850. RealShell::OpenFile(PlatformFile* file, ODBoolean forceOpenApp /*=false*/)
  2851. {
  2852. // if the file is a stationery seed, 
  2853. //    produce mature stationery in the Stationery folder and quit
  2854. // else create a new container if the given file is stationery
  2855. // else open the container and document and current draft and install ShellPlugIns
  2856. // note: file is not consumed and is presumed to be disposed of by the caller
  2857.  
  2858. // 'forceOpenApp' is true when an app containing a document is being launched.
  2859. // (The 'oapp' handler will set this to true.) If so we should assume that this
  2860. // is an OpenDoc document regardless of its filetype, and open it read-only.
  2861.     
  2862.     WatchCursor();
  2863.     ODPlatformType fileType = file->GetPlatformType();
  2864.     
  2865.     ODFileSpec fs = file->GetFileSpec();
  2866.     
  2867.     // ASSERT(the document is at the end of the resource chain)
  2868.  
  2869.     ODSShort numSeeds = Count1Resources(kDocSeedResType);
  2870.     if (numSeeds > 0)
  2871.     {
  2872.         FindStationeryFolder(&(fs.vRefNum), &(fs.parID));
  2873.         file->Specify(&fs);
  2874.         
  2875.         for (;numSeeds;--numSeeds)
  2876.         {
  2877.             Handle            seedEditor;
  2878.             ODContainer*    container;
  2879.             short            unusedID; 
  2880.             ResType            unusedType;
  2881.             Str255            editorName;
  2882.             
  2883.             seedEditor = Get1IndResource(kDocSeedResType, numSeeds);
  2884.             TempODType editor = (ODType)ODNewPtr(GetHandleSize(seedEditor),0);//•minor leak [FIXED]
  2885.             HLock(seedEditor);        //• unnecessary; CFM libs have no segments
  2886.             strcpy((char*)editor, (char*)*seedEditor);
  2887.             HUnlock(seedEditor);
  2888.             GetResInfo(seedEditor, &unusedID, &unusedType, editorName);
  2889.             if (editorName[0] > 31)
  2890.                 ClipStringToBytes( editorName, 31, smCurrentScript );
  2891.             PascalToCString(editorName);
  2892.             CreateTitledContainer(kODNULL, &container, file, (char*)editorName);//•minor leak on exception [FIXED]
  2893.             TempODContainer tempContainer = container; // ensures it's released
  2894.  
  2895.             ODNewDocument(fEV, tempContainer, kODNULL, editor);
  2896.             TempODDocument    newDocument = tempContainer->AcquireDocument(fEV, kODDefaultDocument);
  2897.             TempODDraft newDraft = newDocument->AcquireBaseDraft(fEV, kODDPExclusiveWrite);
  2898.             ODClearIsUnsavedNewDocument(fEV, newDraft);
  2899.             newDraft->Externalize(fEV);
  2900.             file->SetStationery(kODTrue);
  2901.                         
  2902.             RemoveResource(seedEditor);
  2903.         }
  2904.  
  2905.         UpdateResFile(CurResFile());        
  2906.         fDispatcher->Exit(fEV);
  2907.         return kODNULL;    // Didn't open any document
  2908.     }
  2909.     else
  2910.     {
  2911.         PlatformFile*    newFile = kODNULL;
  2912.         ODVolatile(newFile);
  2913.         if (file->IsOpenDocDocument())
  2914.         {                              
  2915.             if (file->IsStationery()) 
  2916.             {
  2917.             TRY
  2918.                 ODContainer*    container = kODNULL;
  2919.                 ODDocument*        document = kODNULL;
  2920.                 ODDraft*        draft = kODNULL;
  2921.                 ODAcquireCtrDocTopDraft(fEV, fSession, file, &container, &document, &draft);
  2922.                 TempODContainer    sContainer = container;
  2923.                 TempODDocument    sDocument = document;
  2924.                 TempODDraft        sDraft = draft;
  2925.     
  2926.                 newFile = new PlatformFile;
  2927.                 newFile->SpecifyFromFile(file);
  2928.                 
  2929.                 container = kODNULL; document = kODNULL;
  2930.                 CreateUntitledContainer(&document, &container, newFile);
  2931.                 TempODContainer    newContainer = container;
  2932.                 TempODDocument    newDocument = document;
  2933.                 
  2934.                 CopyResources(file, newFile);
  2935.                 newDocument->SetBaseDraftFromForeignDraft(fEV, sDraft);    
  2936.                 TempODDraft newDraft = newDocument->AcquireBaseDraft(fEV, kODDPExclusiveWrite);
  2937.                 {
  2938.                 TempODStorageUnit su = newDraft->AcquireDraftProperties(fEV);
  2939.                 ODResetDateModByInfo(fEV, su);
  2940.                 }
  2941.                 {
  2942.                 TempODStorageUnit su = ODAcquireRootPartSUOfDraft(fEV, newDraft);
  2943.                 ODResetDateModByInfo(fEV, su);    
  2944.                 }
  2945.                 ODSetIsUnsavedNewDocument(fEV, newDraft);
  2946.                 newDraft->Externalize(fEV);
  2947.  
  2948.                 newFile->SetPlatformType(file->GetPlatformType());
  2949.                 newFile->SetPlatformCreator(file->GetPlatformCreator());
  2950.                     
  2951.                 { TempODDocumentName name(newFile->GetName());
  2952.                   newDocument->SetName(fEV, name);
  2953.                 }
  2954.                             
  2955.                 file = newFile;
  2956.             CATCH_ALL
  2957.                 if (newFile)
  2958.                 {
  2959.                 TRY
  2960.                     newFile->MoveToTrash();
  2961.                 CATCH_ALL
  2962.                 ENDTRY
  2963.                 }
  2964.                 RERAISE;
  2965.             ENDTRY
  2966.             }
  2967.                         
  2968.         }
  2969.         else if( !forceOpenApp )
  2970.         {            
  2971.             // translate fileType into an OpenDoc kind
  2972.             TempODType theKind = fSession->GetTranslation(fEV)->
  2973.                 GetISOTypeFromPlatformType(fEV, fileType, kODPlatformFileType);
  2974.             
  2975.             // Check to see if fileType is supported by an OpenDoc Editor
  2976.             ODEditor theEditor = fSession->GetBinding(fEV)->ChooseEditorForPart( fEV, kODNULL, theKind );
  2977.             if (!theEditor)
  2978.             {
  2979.                 fDispatcher->Exit(fEV);  
  2980.                 THROW( kODErrCouldNotBindForeignDocument );
  2981.             }
  2982.             
  2983.             // create new File
  2984.             newFile    = new PlatformFile();        //• leak on exception
  2985.             newFile->SpecifyFromFile(file);
  2986.             Str255    fileName;
  2987.             Str255    newName;
  2988.             newFile->GetAsciiName( (char*)fileName, kODMaxFileNameSize );
  2989.             CToPascalString((char*)fileName);
  2990.             { CUsingLibraryResources r;
  2991.                 ReplaceIntoString(kSHLPreODDocNameStrID, fileName,
  2992.                                     kODEmptyPString, newName);
  2993.             }
  2994.             PascalToCString(newName);
  2995.             
  2996.             // Need actual object pointers because of CreateTitledContainer calling conventions
  2997.             ODDocument* document = kODNULL;
  2998.             ODContainer* container = kODNULL;
  2999.             
  3000.             CreateTitledContainer(&document, &container, newFile, (char*)newName);
  3001.             // Now immediately assign to tempobj's to be exception safe.
  3002.             TempODContainer newContainer = container;
  3003.             TempODDocument newDocument = document;
  3004.  
  3005.             HFSFlavor hfsFlavor;
  3006.             hfsFlavor.fileType = fileType;
  3007.             hfsFlavor.fileCreator = file->GetPlatformCreator();
  3008.             hfsFlavor.fdFlags = file->GetFInfoFlags();
  3009.             hfsFlavor.fileSpec = file->GetFileSpec();
  3010.  
  3011.             ((ODUByte*)(&fileType))[0] = kODPlatformKindFileChar1;
  3012.             newFile->SetPlatformType(fileType); 
  3013.             
  3014.             TempODDraft newDraft = newDocument->AcquireBaseDraft(fEV, kODDPExclusiveWrite);
  3015.             TempODStorageUnit su = newDraft->AcquireDraftProperties(fEV);
  3016.             ODResetDateModByInfo(fEV, su);
  3017.  
  3018.             TempODStorageUnit rootPartSU = newDraft->CreateStorageUnit(fEV);
  3019.             ODSetRootPartSUOfDraft(fEV, newDraft, rootPartSU);
  3020.             
  3021.                 // create contents prop/ value for kODApplehfs
  3022.             ODSUAddPropValue(fEV, rootPartSU, kODPropContents, kODApplehfs);
  3023.             StorageUnitSetValue(rootPartSU, fEV, sizeof( hfsFlavor ), &hfsFlavor);
  3024.             rootPartSU->AddValue(fEV, theKind);
  3025.  
  3026.             ODSetISOStrProp(fEV, rootPartSU, kODPropPreferredEditor, kODEditor, theEditor);
  3027.  
  3028.             ODSetIsUnsavedNewDocument(fEV, newDraft);
  3029.             newDraft->Externalize(fEV);
  3030.             file = newFile;
  3031.         }
  3032.         
  3033.         ODDocument *document;
  3034.         ODDraft* topdraft = kODNULL;
  3035.         ODVolatile(topdraft);
  3036.         
  3037.         TRY
  3038.             // Open the document
  3039.             TRY
  3040.                 topdraft = ODOpenFileDocument(fEV, fSession, file,
  3041.                                 forceOpenApp ?kODDPReadOnly :kODDPExclusiveWrite);
  3042.                 this->InstallShellPlugIns(topdraft);
  3043.     
  3044.                 ODOpenDraft(fEV, fSession, topdraft);
  3045.             CATCH_ALL
  3046.                 // Expanding the set of messages users get when something goes really
  3047.                 // wrong opening a draft.  As DH says, if you see this you need to
  3048.                 // fix something right away.  NOTE: this code should be here for a
  3049.                 // *very* short time!
  3050.                 if ( ErrorCode() == kODErrBentoInvalidProperty )    // (should be kODErrBentoErr)
  3051.                     ODShellCorruptDocGoodbye();
  3052.                 else if (( ErrorCode() == -108) || (ErrorCode() == kODErrOutOfMemory) )
  3053.                 //$$$$$ - dh
  3054.                 //This is a VERY TEMPORARY fix for our crashing problems when
  3055.                 //there are problems opening a document. If you see this, alert the
  3056.                 //authorities and immediately work on getting rid of it!!!
  3057.                     ODShellLowMemoryGoodbye();
  3058.                 else
  3059.                     ODShellGenericGoodbye( ErrorCode() != kODErrAlreadyNotified );
  3060.             ENDTRY
  3061.             document = topdraft->GetDocument(fEV);
  3062.             ODReleaseObject(fEV, topdraft);
  3063.  
  3064.             fDispatcher = fSession->GetDispatcher(fEV);
  3065.             fWindowState = fSession->GetWindowState(fEV);
  3066.             fArbitrator = fSession->GetArbitrator( fEV );
  3067.         
  3068.             ODFileSpec fileFSSpec = file->GetFileSpec();
  3069.     
  3070.             LMSetSFSaveDisk(-(fileFSSpec.vRefNum));
  3071.             LMSetCurDirStore(fileFSSpec.parID);
  3072.             ODDeleteObject(newFile);
  3073.         CATCH_ALL
  3074.             this->CheckFreeMemory();
  3075.             if (topdraft)
  3076.             {
  3077.                 ODDocument* document = topdraft->GetDocument(fEV);
  3078.                 ODSafeReleaseObject(topdraft);
  3079.                 if (ODCloseDocument(fEV, fSession, document))
  3080.                     fDispatcher->Exit(fEV);
  3081.             }    
  3082.             this->SetAEError(ErrorCode());
  3083.         ENDTRY
  3084.         ArrowCursor();
  3085.         
  3086.         return document;
  3087.     }
  3088. }    // RealShell::OpenFile
  3089.  
  3090. //------------------------------------------------------------------------------
  3091. // RealShell::OpenAnotherFile
  3092. //------------------------------------------------------------------------------
  3093.  
  3094. void    RealShell::OpenAnotherFile(PlatformFile* file,
  3095.                                     AEDescList* replyInfo, 
  3096.                                     ODBoolean deleteOnFailure,
  3097.                                     ODBoolean unsavedDoc)
  3098. {
  3099.     // launch another document stub to open the passed in PlatformFile
  3100.     OSErr err = noErr;
  3101.     ODFileSpec theDocument = file->GetFileSpec();
  3102.     if (WasLaunchedThenActivate(&theDocument,  kAEOpenDocuments, err))
  3103.         return;
  3104.             
  3105.     ODSLong    savedRefNum;
  3106.     BeginUsingLibraryResources(savedRefNum);
  3107.     AEDesc docDesc;
  3108.     ProcessSerialNumber psn;
  3109.     err = AECreateDesc( typeFSS, &theDocument, sizeof(theDocument),
  3110.             &docDesc );
  3111.     if ( !err )
  3112.     {
  3113.         err = VerifyAndLaunchDocumentStub(&docDesc, replyInfo, &psn,
  3114.                 kAEOpenDocuments, kODNULL, unsavedDoc);
  3115.         AEDisposeDesc( &docDesc );
  3116.     }
  3117.     EndUsingLibraryResources(savedRefNum);
  3118.     if ( err ) {
  3119.         if( deleteOnFailure )
  3120.             file->Delete();
  3121.         THROW( err );
  3122.     } else if( deleteOnFailure ) {
  3123.         // Remember PSN and spec in case launch fails; CFM will send us an error and
  3124.         // we can then delete the new file. See HandleLaunchFailedEvent...
  3125.         fLastNewDocPSN = psn;
  3126.         fLastNewDocSpec= file->GetFileSpec();
  3127.     }
  3128. }
  3129.  
  3130. //------------------------------------------------------------------------------
  3131. // OpenFileFilter
  3132. //
  3133. //    Return true (don't show this item) for invisible files and folders
  3134. //
  3135. //    Addendum: There appears to be no way to filter out invisible folders, since
  3136. //    thie function is only passed files. Oh well. Leaving code in anyway in case
  3137. //    this changes.
  3138. //------------------------------------------------------------------------------
  3139.  
  3140. static pascal Boolean OpenFileFilter(CInfoPBPtr fileInfo)
  3141. {
  3142.     if (fileInfo->hFileInfo.ioFlAttrib & ioDirMask) // FOLDER
  3143.     {
  3144.         if (fileInfo->dirInfo.ioDrUsrWds.frFlags & fInvisible)
  3145.             return true;
  3146.     }
  3147.     else // FILE
  3148.     {
  3149.         if (fileInfo->hFileInfo.ioFlFndrInfo.fdFlags & fInvisible)
  3150.             return true;
  3151.     }
  3152.  
  3153.     return false;
  3154. }
  3155.  
  3156. //------------------------------------------------------------------------------
  3157. // RealShell::OpenStdFile
  3158. //------------------------------------------------------------------------------
  3159.  
  3160. void    RealShell::OpenStdFile()
  3161. {
  3162.     // call display StdFile (with all documents) and open document in a new shell
  3163.     ArrowCursor();
  3164.     StandardFileReply sfReply;
  3165.     SFTypeList sfTypes;
  3166.     
  3167.     fWindowState->DeactivateFrontWindows(fEV);
  3168.  
  3169.     FileFilterUPP openFileFilterUPP = NewFileFilterProc(OpenFileFilter);
  3170.     StandardGetFile((FileFilterUPP)openFileFilterUPP, -1, sfTypes, &sfReply);
  3171.     DisposeRoutineDescriptor(openFileFilterUPP);
  3172.  
  3173.     fWindowState->ActivateFrontWindows(fEV);
  3174.  
  3175.     if (sfReply.sfGood) 
  3176.     {
  3177.         TempPlatformFile file = new PlatformFile();
  3178.         file->Specify(&sfReply.sfFile);
  3179.         if( ! file->IsOpenDocDocument() )
  3180.         {
  3181.             THROW_IF_ERROR( SendFinderODOCEvent( &sfReply.sfFile ) );
  3182.  
  3183.             // Fix #1221901:
  3184.             // else (if creator≠ kODShellSignature)
  3185.             // 'appl' = launch application
  3186.             // else 'snd ' = play sound
  3187.             // else 'cdev' = open control panel
  3188.             // else use MEO,desktop database to find appropriate application to use,
  3189.             //    then launch application with document
  3190.         } else {
  3191.             // Open document in this process if I am an application process
  3192.             // with the same signature as the doc; e.g. CyberDog.
  3193.             // Otherwise launch doc into a new OD process.
  3194.             ProcessInfoRec info;
  3195.             GetCurrentProcessInfo(&info);
  3196.             if( info.processType=='APPL' && info.processSignature==file->GetPlatformCreator() )
  3197.                 this->OpenFile(file);
  3198.             else
  3199.                 this->OpenAnotherFile(file);
  3200.         }
  3201.     }
  3202. }
  3203.  
  3204. //-------------------------------------------------------------------------------------
  3205. // DoesUserCancelClose
  3206. //
  3207. //    To do: Fix flow of control
  3208. //-------------------------------------------------------------------------------------
  3209.  
  3210. ODBoolean    RealShell::DoesUserCancelClose(ODDocument* document, DescType saveOptions)
  3211. {
  3212. // asks user "Save changes before closing? Discard Changes, Cancel , Save"
  3213.     ODBoolean stillSave;
  3214.     switch(saveOptions)
  3215.     {
  3216.         case kAEAsk:
  3217.         {
  3218.             if (AEInteractWithUser(kNoTimeOut, NULL, NULL) != noErr)
  3219.                 return kODTrue;
  3220.             ArrowCursor();
  3221.             char    fileName[256];
  3222.             ODGetDocumentFileName(fEV, document, &(fileName[0]));
  3223.             CToPascalString(fileName);
  3224.  
  3225.  
  3226.             ODSShort btnClicked;
  3227.             if (ODIsTempDocument(fEV, fSession, document))
  3228.             {
  3229.                 if (ODIsUnsavedNewDocument(fEV, fSession, document))
  3230.                     btnClicked = kSHLscNo;
  3231.                 else
  3232.                     btnClicked = kSHLscOK;
  3233.             }
  3234.             else
  3235.             {
  3236.                 ODSLong        savedRefNum;
  3237.                 BeginUsingLibraryResources(savedRefNum);
  3238.                 ParamText((unsigned char const *)fileName, kODEmptyPString, 
  3239.                             kODEmptyPString, kODEmptyPString);
  3240.                 fWindowState->DeactivateFrontWindows(fEV);
  3241.                 TRY
  3242.                 {
  3243.                     DialogPtr askSaveDlg = kODNULL;
  3244.                     askSaveDlg = ODGetNewDialog( fEV, kSHLsvChanges, fSession, kODTrue );
  3245.                     THROW_IF_NULL( askSaveDlg );
  3246.                     ODUseCommandKeyStringsResource( kSHLsvChangesCmdKeyStrs );
  3247.                     ::ShowWindow( askSaveDlg );
  3248. //                    FIX_THIS_PLACE
  3249.                     ::ModalDialog( GetODButtonKeyFilterProc(), &btnClicked );
  3250.                     ::DisposeDialog( askSaveDlg );
  3251.                 }
  3252.                 CATCH_ALL
  3253.                 {
  3254.                     btnClicked = kSHLscCancel;        // Cancel the close
  3255.                 }
  3256.                 ENDTRY
  3257.      
  3258.                 fWindowState->ActivateFrontWindows(fEV);
  3259.     
  3260.                 EndUsingLibraryResources(savedRefNum);
  3261.             }
  3262.             if (btnClicked == kSHLscCancel)
  3263.                 return kODTrue;
  3264.             else if (btnClicked == kSHLscNo &&
  3265.                      ODIsUnsavedNewDocument(fEV, fSession, document))
  3266.             {
  3267.                 TempPlatformFile file = 
  3268.                     GetPlatformFileFromContainer(fEV, document->GetContainer(fEV));
  3269.                 file->MoveToTrash();
  3270.             }
  3271.                 
  3272.             stillSave = (btnClicked == kSHLscOK);
  3273.         }
  3274.             break;
  3275.         case kAEYes:
  3276.             stillSave = kODTrue;
  3277.             break;
  3278.         case kAENo:
  3279.             stillSave = kODFalse;
  3280.             break;
  3281.         default:
  3282.             THROW(errAETypeError);
  3283.     }
  3284.  
  3285.     if (stillSave) 
  3286.     {
  3287.         if (this->Save(document, kODTrue, saveOptions))
  3288.             ;
  3289.         else // The user canceled the Save As dialog, which cancels the close
  3290.             return kODTrue;
  3291.     }
  3292.     return kODFalse;
  3293. }
  3294.  
  3295.  
  3296. void    RealShell::CloseWindow(ODPlatformWindow pwindow, DescType saveOptions)
  3297. {
  3298.     if (pwindow==kODNULL)
  3299.     {
  3300.         fDispatcher->Exit(fEV);
  3301.         return;
  3302.     }
  3303.     
  3304.     if (!fWindowState->IsODWindow(fEV,pwindow))
  3305.     {
  3306.         ASSERT(fWindowState->IsODWindow(fEV,pwindow), kODErrClosingNonODWindow);
  3307.         return;
  3308.     }
  3309.     
  3310.     ODWindow*  window = fWindowState->AcquireODWindow(fEV,pwindow);
  3311.     if (!window)
  3312.         return;    
  3313.  
  3314.     ODDraft* draft = window->GetDraft(fEV);
  3315.     ODDocument* document = draft->GetDocument(fEV);
  3316.     ODBoolean isOnlyTopDraftWindow =
  3317.         window->IsRootWindow(fEV) && (fWindowState->GetRootWindowCount(fEV,draft) == 1) && 
  3318.         (!(document->Exists(fEV, kODNULLID, draft, kODPosFirstAbove)));
  3319.  
  3320.     if (isOnlyTopDraftWindow &&
  3321.         ODDraftHasWriteAccess(fEV, draft) &&
  3322.         (draft->ChangedFromPrev(fEV) || ODIsUnsavedNewDocument(fEV, fSession, document)))
  3323.     {
  3324.         if (saveOptions == kAEYes)
  3325.         {
  3326.             ODSaveDocument(fEV, fSession, document);
  3327.         }
  3328.         else 
  3329.         {
  3330.             ODReleaseObject(fEV, window);    // balances AcquireODWindow above
  3331.  
  3332.             if (this->DoesUserCancelClose(document, saveOptions))
  3333.                 return;
  3334.                 
  3335.             window = fWindowState->AcquireODWindow(fEV,pwindow); // reacquire because user did not cancel close
  3336.             // NOTE: If the user SAVED the document inside the DoesUserCancelClose 
  3337.             // call above for the first time, (thereby using StdFile), and to a 
  3338.             // different volume, then DoesUserCancelClose did NOT reopen the document,
  3339.             // and pwindow is no longer a valid WindowPtr.  Therefore, the windowstate 
  3340.             // does not find it, and return kODNULL which causes the same code 
  3341.             // execution as if the return statement above was executed.
  3342.         }
  3343.     }
  3344.     
  3345.     if (window)
  3346.         if (ODReleaseCloseWindow(fEV, fSession, window)) // balances AcquireODWindow above
  3347.             fDispatcher->Exit(fEV);
  3348. }
  3349.  
  3350. //------------------------------------------------------------------------------
  3351. // RealShell::CloseDocument
  3352. //
  3353. //    Result of true means that document was closed (or close was attempted).
  3354. //    Result of false means that the process was cancelled. 
  3355. //------------------------------------------------------------------------------
  3356.  
  3357. ODBoolean RealShell::CloseDocument(ODDocument* document, DescType saveOptions)
  3358. {
  3359.     ODDraft*    draft = ODGetTempDraftFromOpenDocument(fEV, fSession, document);
  3360.     ODBoolean    result = kODTrue;
  3361.     
  3362.     if (draft != kODNULL &&
  3363.         ODDraftHasWriteAccess(fEV, draft) &&
  3364.         (draft->ChangedFromPrev(fEV) || ODIsUnsavedNewDocument(fEV, fSession,
  3365.                                                                 document)))
  3366.     {
  3367.         if (this->DoesUserCancelClose(document, saveOptions))
  3368.             result = kODFalse;
  3369.     }
  3370.     if (result == kODTrue)
  3371.     {
  3372.         if (ODCloseDocument(fEV, fSession, document))
  3373.             fDispatcher->Exit(fEV);
  3374.     }
  3375.  
  3376.     return result;
  3377. }
  3378.  
  3379. //------------------------------------------------------------------------------
  3380. // RealShell::DeleteDocument
  3381. //------------------------------------------------------------------------------
  3382.  
  3383. void RealShell::DeleteDocument(ODDocument* document)
  3384. {
  3385.     // First, ask the user if they are sure they want to delete!
  3386.     if (!IsOptionKeyDown())
  3387.     {
  3388.         ArrowCursor();
  3389.     
  3390.         char    fileName[256];
  3391.         ODGetDocumentFileName(fEV, document, &(fileName[0]));
  3392.         CToPascalString(fileName);
  3393.     
  3394.         ODSLong        savedRefNum;
  3395.         BeginUsingLibraryResources(savedRefNum);
  3396.     
  3397.         ParamText(kODEmptyPString, (unsigned char const *)fileName, 
  3398.                     kODEmptyPString, kODEmptyPString);
  3399.     
  3400.         fWindowState->DeactivateFrontWindows(fEV);
  3401.         
  3402.         ODSShort btnClicked;
  3403.         TRY
  3404.         {
  3405.             DialogPtr askRevertDlg = kODNULL;
  3406.             askRevertDlg = ODGetNewDialog( fEV, kSHLDeleteDLOG, fSession, kODTrue );
  3407.             THROW_IF_NULL( askRevertDlg );
  3408.             ODUseCommandKeyStringsResource( kSHLDeleteDLOGCmdKeyStrs );
  3409.             ::ShowWindow( askRevertDlg );
  3410.             ::ModalDialog( GetODButtonKeyFilterProc(), &btnClicked );
  3411.             ::DisposeDialog( askRevertDlg );
  3412.         }
  3413.         CATCH_ALL
  3414.         {
  3415.             btnClicked = kSHLscCancel;        // Cancel the delete
  3416.         }
  3417.         ENDTRY;
  3418.     
  3419.         fWindowState->ActivateFrontWindows(fEV);
  3420.     
  3421.         EndUsingLibraryResources(savedRefNum);
  3422.         if (!(kSHLscOK == btnClicked))
  3423.             return;
  3424.     }
  3425.     
  3426.     TempPlatformFile    
  3427.         currentFile = GetPlatformFileFromContainer(fEV, document->GetContainer(fEV));                            
  3428.  
  3429.     ODSaveDocument(fEV, fSession, document);
  3430.     if (ODCloseDocument(fEV, fSession, document))
  3431.         fDispatcher->Exit(fEV);
  3432.         
  3433.     currentFile->MoveToTrash();
  3434. }
  3435.  
  3436. //-------------------------------------------------------------------------------------
  3437. // Save
  3438. //-------------------------------------------------------------------------------------
  3439.  
  3440. ODBoolean    RealShell::Save(ODDocument* document, ODBoolean isClosing, ODDescType saveOptions)
  3441. {    
  3442.     if (ODIsUnsavedNewDocument(fEV, fSession, document) && saveOptions == kAEAsk)
  3443.     {
  3444.         StandardFileReply reply;
  3445.         Str255 fileName;
  3446.         ODBoolean            wasStationery;
  3447.  
  3448.         ODGetDocumentFileName(fEV, document, (char*)&(fileName[0]));
  3449.         CToPascalString((char*)fileName);
  3450.         
  3451.         Str255 msg;                
  3452.         { CUsingLibraryResources r;
  3453.             GetIndString(msg, kSHLStrsID, kSHLStrIndDSaveAs);
  3454.         }
  3455.         
  3456.         TempPlatformFile
  3457.             currentFile = GetPlatformFileFromContainer(fEV, document->GetContainer(fEV));
  3458.         wasStationery = currentFile->IsStationery();
  3459.         
  3460.         // Need to rename file on disk briefly to avoid erroneous "Replace?" dialog
  3461.         
  3462.         // $$$$$ DOES NOT ACCOUNT FOR THE CASE WHERE THE filename+" " already exists !!!!!!
  3463.         
  3464.         FSSpec currentFSSpec = currentFile->GetFileSpec();
  3465.         if (currentFSSpec.name[0] < kODMaxFileNameSize)
  3466.             currentFSSpec.name[++currentFSSpec.name[0]] = 0x20;
  3467.         else
  3468.             --currentFSSpec.name[0];
  3469.         
  3470.         TRY
  3471.             currentFile->Rename(currentFSSpec.name);
  3472.         CATCH_ALL
  3473.             WARN("Unable to rename to avoid replace dialog. One replace dialog coming up!");
  3474.         ENDTRY
  3475.         
  3476.         // This would be cleaner, but not optimal
  3477.         // currentFile->UniquifyName(,,,,kRenameInPlace);
  3478.         
  3479.         ODDraft* draft = ODGetTempDraftFromOpenDocument(fEV, fSession, document);
  3480.         ODBoolean isStationery = 
  3481.             this->AskUserWhereToPutIt(draft, fileName, msg, &reply );
  3482.  
  3483.         if (!reply.sfGood) 
  3484.         {
  3485.             TRY
  3486.                 currentFile->Rename(fileName);
  3487.             CATCH_ALL
  3488.             ENDTRY
  3489.             return kODFalse;
  3490.         }
  3491.         
  3492.         {
  3493.             // This assumes that the front window is the one being saved.
  3494.             // This might not be true for scripting, although it is right now
  3495.             // since we can only script the front window.
  3496.             TempODWindow window = fWindowState->AcquireFrontRootWindow(fEV);
  3497.             TempPlatformFile usersFile = ODGetFileIfRoot(fEV,
  3498.                                     window->GetRootFacet(fEV)->GetFrame(fEV));
  3499.             if (usersFile)
  3500.                 usersFile->SetStationery(isStationery);
  3501.             // RESET INITED BIT OF FILE. THE FINDER HAS A BUG
  3502.             //    WHERE IT WON'T UPDATE THE ICON IN THE FINDER IF ONLY THE
  3503.             //    STATIONERY BIT IS CHANGED.
  3504.             if (wasStationery != isStationery
  3505.                     && usersFile->IsEqualTo(currentFile))
  3506.                 usersFile->UnsetFinderFlag(kHasBeenInited);
  3507.         }
  3508.         
  3509.         TempPlatformFile file = new PlatformFile();
  3510.         file->Specify(&reply.sfFile);
  3511.         
  3512.         if (file->IsEqualTo(currentFile))
  3513.             ; // do nothing, we'll save down below right ontop of the current document.
  3514.         else 
  3515.         {
  3516.             if (reply.sfReplacing)
  3517.             {
  3518.                 TRY
  3519.                     file->Delete();
  3520.                 CATCH_ALL
  3521.                     THROW(kODErrCannotSaveAsOntoBusyDoc);
  3522.                 ENDTRY;
  3523.             }
  3524.             
  3525.             if (reply.sfFile.vRefNum == currentFile->GetFileSpec().vRefNum)
  3526.             {
  3527.                 currentFile->MoveRename(&(reply.sfFile), kODFalse);
  3528.             }
  3529.             else
  3530.             {
  3531.                 if (!isClosing)
  3532.                     this->ShowSaveDiffVolDialog();
  3533.                 
  3534.                 ODSaveDocument(fEV, fSession, document);
  3535.                 ODBoolean wasLastDocument = ODCloseDocument(fEV, fSession, document);
  3536.                 file->CopyFrom(currentFile);
  3537.                 currentFile->Delete();
  3538.                 if (!isClosing) 
  3539.                 {
  3540.                     ODDraft* topdraft = ODOpenFileDocument(fEV, fSession, file, kODDPExclusiveWrite);
  3541.                     document = topdraft->GetDocument(fEV);
  3542.                     this->InstallShellPlugIns(topdraft);
  3543.             
  3544.                     ODOpenDraft(fEV, fSession, topdraft);
  3545.                     this->CloseSaveDiffVolDialog();
  3546.                     
  3547.                     ODReleaseObject(fEV, topdraft);
  3548.         
  3549.                     fDispatcher = fSession->GetDispatcher(fEV);
  3550.                     fWindowState = fSession->GetWindowState(fEV);
  3551.                     fArbitrator = fSession->GetArbitrator( fEV );
  3552.                 }
  3553.                 else
  3554.                 {
  3555.                  if (wasLastDocument)
  3556.                     fDispatcher->Exit(fEV);
  3557.                 }
  3558.                 
  3559.                 LMSetSFSaveDisk(-(reply.sfFile.vRefNum));
  3560.                 LMSetCurDirStore(reply.sfFile.parID);
  3561.             }
  3562.         }
  3563.     }
  3564.  
  3565.     ODSetIsTempDocument(fEV, ODGetTempDraftFromOpenDocument(fEV, fSession, document), kODFalse);
  3566.     ODSaveDocument(fEV, fSession, document);
  3567.     return kODTrue;
  3568. }    // RealShell::Save
  3569.  
  3570. void RealShell::ShowSaveDiffVolDialog( )
  3571. {
  3572.     if( !fSaveDiffVolDialog ) {
  3573.         CUsingLibraryResources r;
  3574.         fSaveDiffVolDialog = ::GetNewDialog(kSHLSaveDiffVolDialogID,kODNULL,(WindowPtr)-1L);
  3575.         ::ShowWindow(fSaveDiffVolDialog);
  3576.         ::DrawDialog(fSaveDiffVolDialog);
  3577.     }
  3578. }
  3579.  
  3580. void RealShell::CloseSaveDiffVolDialog( )
  3581. {
  3582.     if( fSaveDiffVolDialog ) {
  3583.         CUsingLibraryResources r;
  3584.         ::DisposeDialog(fSaveDiffVolDialog);
  3585.         fSaveDiffVolDialog = kODNULL;
  3586.     }
  3587. }
  3588.  
  3589. //-------------------------------------------------------------------------------------
  3590. // Save A Copy
  3591. //-------------------------------------------------------------------------------------
  3592.  
  3593. pascal void DrawSmallIcon(DialogPtr theDialog, short theItem)
  3594. {
  3595.     short  itemHit;
  3596.     Handle scratchHandle;
  3597.     Rect   scratchRect;
  3598.     
  3599.     GetDialogItem(theDialog, theItem, &itemHit, &scratchHandle, &scratchRect);
  3600.  
  3601.     (void) PlotIconID (&scratchRect, atNone, ttNone,
  3602.                        theItem == kSHLSaCDocumentIconItem ? kSHLSaCDocumentIconID : kSHLSaCStationeryIconID);
  3603. }
  3604.  
  3605. pascal short SaveCopyDlgHook(short item, DialogPtr theDialog, void *saveDataPtr)
  3606. {
  3607.     short  itemHit;
  3608.     Handle scratchHandle;
  3609.     Rect   scratchRect;
  3610.     ODSShort     translateItem = 0;
  3611.     ODSShort     currentKindItem = 0;
  3612.     
  3613.     UserItemUPP drawSmallIconUPP = ((SaveCopyStruct*)saveDataPtr)->iconUPP;
  3614.     
  3615.     if ( ((WindowPeek)theDialog)->refCon == sfMainDialogRefCon )
  3616.         switch (item) {
  3617.         case sfHookFirstCall:
  3618.             GetDialogItem(theDialog, kSHLSaCDocumentIconItem, &itemHit, &scratchHandle, &scratchRect);
  3619.             SetDialogItem(theDialog, kSHLSaCDocumentIconItem, itemHit, (Handle) drawSmallIconUPP, &scratchRect);
  3620.     
  3621.             GetDialogItem(theDialog, kSHLSaCStationeryIconItem, &itemHit, &scratchHandle, &scratchRect);
  3622.             SetDialogItem(theDialog, kSHLSaCStationeryIconItem, itemHit, (Handle) drawSmallIconUPP, &scratchRect);
  3623.             
  3624.             GetDialogItem(theDialog, kSHLSaCDocumentRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3625.             SetControlValue( (ControlHandle) scratchHandle, !((SaveCopyStruct*)saveDataPtr)->makeStationery);
  3626.     
  3627.             GetDialogItem(theDialog, kSHLSaCStationeryRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3628.             SetControlValue( (ControlHandle) scratchHandle, ((SaveCopyStruct*)saveDataPtr)->makeStationery);
  3629.             
  3630.             GetDialogItem(theDialog, kSHLSaCKindPopupItem, &itemHit, &scratchHandle, &scratchRect);
  3631.             MenuHandle kindMenu = GetMenu(kSHLSaCKindPopupMenu);
  3632.             THROW_IF_NULL(kindMenu);
  3633.  
  3634.             InitKindsPopup(((SaveCopyStruct*)saveDataPtr)->kindList, 
  3635.                             ((SaveCopyStruct*)saveDataPtr)->partKind, 
  3636.                             (ControlHandle)scratchHandle, 
  3637.                             ¤tKindItem, kindMenu, &translateItem,
  3638.                             ((SaveCopyStruct*)saveDataPtr)->session);
  3639.             break;
  3640.     
  3641.         case kSHLSaCDocumentRadioBtn :
  3642.             GetDialogItem(theDialog, kSHLSaCDocumentRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3643.             SetControlValue( (ControlHandle) scratchHandle, 1);
  3644.             GetDialogItem(theDialog, kSHLSaCStationeryRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3645.             SetControlValue( (ControlHandle) scratchHandle, 0);
  3646.             
  3647.             break;
  3648.             
  3649.         case kSHLSaCStationeryRadioBtn :
  3650.             GetDialogItem(theDialog, kSHLSaCDocumentRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3651.             SetControlValue( (ControlHandle) scratchHandle, 0);
  3652.             GetDialogItem(theDialog, kSHLSaCStationeryRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3653.             SetControlValue( (ControlHandle) scratchHandle, 1);
  3654.     
  3655.             break;
  3656.             
  3657.         case sfHookLastCall :
  3658.             /* check value of radio buttons and save accordingly */
  3659.             GetDialogItem(theDialog, kSHLSaCStationeryRadioBtn, &itemHit, &scratchHandle, &scratchRect);
  3660.             ((SaveCopyStruct*)saveDataPtr)->makeStationery = GetControlValue( (ControlHandle) scratchHandle);
  3661.             ((SaveCopyStruct*)saveDataPtr)->changeKind = kODNULL;
  3662.             GetDialogItem(theDialog, kSHLSaCKindPopupItem, &itemHit, &scratchHandle, &scratchRect);
  3663.             ODSShort kindItem = (ODSShort) GetControlValue((ControlHandle)scratchHandle);
  3664.             if (kindItem != currentKindItem)
  3665.             {
  3666.                 ODType newKind = GetThisKindFromList(kindItem,
  3667.                                     ((SaveCopyStruct*)saveDataPtr)->kindList);
  3668.                 ((SaveCopyStruct*)saveDataPtr)->changeKind = newKind;
  3669.             }
  3670.         
  3671.             break;
  3672.         }
  3673.                                                                                                                                 
  3674.     return (item);
  3675. }
  3676.  
  3677. ODBoolean RealShell::AskUserWhereToPutIt( ODDraft* whichDraft, Str255 defaultName,
  3678.         Str255 msg, StandardFileReply* reply )
  3679. {
  3680.     Point              pt;
  3681.     SetPt(&pt, 0, 0);
  3682.  
  3683.     ODBoolean    makeStationery;
  3684.  
  3685.     ODSLong        savedRefNum;
  3686.         // Setup fSaveCopyData fields for custom put file
  3687.     fSaveCopyData = new SaveCopyStruct;
  3688.  
  3689.     fSaveCopyData->session = this->GetSession();
  3690.     TempODPart rootPart = ODAcquireRootPartOfDraft(fEV, whichDraft);
  3691.     
  3692.     ODContainer* container = whichDraft->GetDocument(fEV)->GetContainer(fEV);
  3693.     TempPlatformFile file = GetPlatformFileFromContainer(fEV, container);
  3694.     fSaveCopyData->makeStationery = file->IsStationery();
  3695. //    fSaveCopyData->makeStationery = kODFalse; // always default to saving a document
  3696.     
  3697.  
  3698.     fSaveCopyData->partKind = ODGetKind(fEV, rootPart );
  3699.     fSaveCopyData->kindList = 
  3700.         fSession->GetStorageSystem(fEV)->CreateTypeList(fEV, kODNULL);
  3701.  
  3702.         // get StorageUnit kinds
  3703.     ContentValueTypes(rootPart->GetStorageUnit(fEV), fSaveCopyData->kindList);
  3704.  
  3705.         // get all kinds supported by this editor
  3706.     ODNameSpaceManager* nsm = fSaveCopyData->session->GetNameSpaceManager(fEV);
  3707.     ODEditor editorID = GetCurrentEditorForPart(rootPart);
  3708.     GetAllKindsForEditor(nsm, fSaveCopyData->kindList, editorID);
  3709.     ODDisposePtr(editorID);
  3710.     
  3711.     BeginUsingLibraryResources(savedRefNum);
  3712.     fSaveCopyData->iconUPP = NewUserItemProc(DrawSmallIcon);
  3713.     DlgHookYDUPP saveACopyUPP = NewDlgHookYDProc(SaveCopyDlgHook);
  3714.  
  3715.     fWindowState->DeactivateFrontWindows(fEV);
  3716.     
  3717.     {
  3718.     TempODMenuBar currentMenuBar = fWindowState->AcquireCurrentMenuBar(fEV);
  3719.     ODDialogBegin(fEV, fSession, currentMenuBar, kODNULL);
  3720.     CustomPutFile(msg, defaultName, reply,
  3721.                   kSHLSaveCopyDlgID, pt, saveACopyUPP, kODNULL, kODNULL , kODNULL, fSaveCopyData);
  3722.     ODDialogEnd();
  3723.     }
  3724.  
  3725.     fWindowState->ActivateFrontWindows(fEV);
  3726.  
  3727.     DisposeRoutineDescriptor(saveACopyUPP);    
  3728.     DisposeRoutineDescriptor(fSaveCopyData->iconUPP);
  3729.      EndUsingLibraryResources(savedRefNum);
  3730.  
  3731.     makeStationery = fSaveCopyData->makeStationery;
  3732.     
  3733.     ODDisposePtr( fSaveCopyData->partKind );
  3734.     ODDeleteObject( fSaveCopyData->kindList );
  3735.     ODDeleteObject( fSaveCopyData );
  3736.     
  3737.      return makeStationery;
  3738. }
  3739.  
  3740. void RealShell::SaveACopy(ODDraft* draft)        
  3741. {
  3742. // save a copy of the topmost draft into a new container
  3743.     StandardFileReply reply;
  3744.     
  3745.     Str255 msg;
  3746.     
  3747.     ODDocument* document = draft->GetDocument(fEV);
  3748.     
  3749.     Str255 fileName;
  3750.     ODGetDocumentFileName(fEV, document, (char*)&(fileName[0]));
  3751.     CToPascalString((char*)fileName);
  3752.     
  3753.     Str255 defaultName;
  3754.     
  3755.     // HI$ #1247070: should we append " Draft <n>" if the user happens to be saving
  3756.     // a copy of a draft?
  3757.     
  3758.     { CUsingLibraryResources r;
  3759.         GetIndString(msg, kSHLStrsID, kSHLStrIndDSaveACopy);
  3760.         ReplaceIntoString(kSHLCopyDefaultStrID, fileName, kODEmptyPString, defaultName);
  3761.     }
  3762.     if (defaultName[0] > kODMaxFileNameSize)
  3763.         ClipStringToBytes( defaultName, kODMaxFileNameSize, smCurrentScript );
  3764.     
  3765.     ODBoolean isStationery = 
  3766.         this->AskUserWhereToPutIt(draft, defaultName, msg, &reply );
  3767.     if (!reply.sfGood) 
  3768.         return;
  3769.     
  3770.     TempPlatformFile file = new PlatformFile();
  3771.     file->Specify(&reply.sfFile);
  3772.     
  3773.     TempPlatformFile
  3774.         currentFile = GetPlatformFileFromContainer(fEV, document->GetContainer(fEV));
  3775.  
  3776.     if (reply.sfReplacing)
  3777.     {
  3778.         ODBoolean isEqual = file->IsEqualTo(currentFile);
  3779.         
  3780.         if (isEqual != kODFalse)
  3781.         {
  3782.             THROW(kODErrCannotSaveACopyOntoCurrentDoc);
  3783.         }
  3784.         
  3785.         TRY
  3786.             file->Delete();
  3787.         CATCH_ALL
  3788.             THROW(kODErrCannotSaveACopyOntoBusyDoc);
  3789.         ENDTRY;
  3790.     }
  3791.     
  3792.     ODSaveACopyOfDraft(fEV, fSession, draft, file);
  3793.     file->SetStationery(isStationery);
  3794.     CopyResources(currentFile, file); // copy the resource over to the new copy
  3795. }
  3796.  
  3797.  
  3798. void
  3799. RealShell::CloseAllDocs( DescType /* saveOptions */ ) // will be handled by
  3800.                                                         // quit handler
  3801. {
  3802.     // CyberDog wants to intercept the quit apple event, so send ourselves one.
  3803.  
  3804.     ProcessSerialNumber    psn = {0, kCurrentProcess};
  3805.     OSErr                error = noErr;
  3806.     AEAddressDesc        address = {typeNull, NULL};
  3807.     AppleEvent            message = {typeNull, NULL};
  3808.     AppleEvent            reply = {typeNull, NULL};
  3809.  
  3810.     ODVolatile(error);
  3811.  
  3812.     TRY
  3813.         THROW_IF_ERROR(AECreateDesc(typeProcessSerialNumber, (Ptr)&psn, sizeof(psn),
  3814.                                     &address));
  3815.         THROW_IF_ERROR(AECreateAppleEvent(kCoreEventClass, kAEQuitApplication,
  3816.                         &address, kAutoGenerateReturnID, kAnyTransactionID,
  3817.                         &message));
  3818.         THROW_IF_ERROR(AESend(&message, &reply,
  3819.                                 kAENoReply + kAECanInteract,
  3820.                                 kAENormalPriority, kAEDefaultTimeout,
  3821.                                 (AEIdleUPP)kODNULL, (AEFilterUPP)kODNULL));
  3822.     CATCH_ALL
  3823.         error = ErrorCode();
  3824.     ENDTRY
  3825.  
  3826.     AEDisposeDesc(&address);
  3827.       AEDisposeDesc(&message);
  3828.       AEDisposeDesc(&reply);
  3829.  
  3830.     THROW_IF_ERROR(error);
  3831.  
  3832. #if 0
  3833.     for( TempODWindowIterator wi(fEV,fSession->GetWindowState(fEV)); wi; ++wi ) {
  3834.         ODDocument *document = ODGetDraftOfWindow(fEV,wi)->GetDocument(fEV);
  3835.         if( ! this->CloseDocument(document, saveOptions) )
  3836.             return; /* user canceled */
  3837.     }
  3838.     // CloseDocument method will tell dispatcher to exit when last doc closes.
  3839. #endif /* 0 */
  3840. }
  3841.  
  3842.  
  3843. //-------------------------------------------------------------------------------------
  3844. // Revert
  3845. //-------------------------------------------------------------------------------------
  3846.  
  3847.  
  3848. void    RealShell::Revert(ODDocument* document)
  3849. {
  3850.     if (this->DoesUserOKRevert(document)) 
  3851.     {
  3852.         ODRevertDocument(fEV, fSession, document);
  3853.     }
  3854. }
  3855.  
  3856. ODBoolean    RealShell::DoesUserOKRevert(ODDocument* document)
  3857. {
  3858. // asks user "Revert to the last saved version?"
  3859.  
  3860.     ArrowCursor();
  3861.  
  3862.     char    fileName[256];
  3863.     ODGetDocumentFileName(fEV, document, &(fileName[0]));
  3864.     CToPascalString(fileName);
  3865.  
  3866.     ODSLong        savedRefNum;
  3867.     BeginUsingLibraryResources(savedRefNum);
  3868.  
  3869.     ParamText(kODEmptyPString, (unsigned char const *)fileName, 
  3870.                 kODEmptyPString, kODEmptyPString);
  3871.  
  3872.     fWindowState->DeactivateFrontWindows(fEV);
  3873.     
  3874.     ODSShort btnClicked;
  3875.     TRY
  3876.     {
  3877.         DialogPtr askRevertDlg = kODNULL;
  3878.         askRevertDlg = ODGetNewDialog( fEV, kSHLsvRevert, fSession, kODTrue );
  3879.         THROW_IF_NULL( askRevertDlg );
  3880.         ODUseCommandKeyStringsResource( kSHLsvRevertCmdKeyStrs );
  3881.         ::ShowWindow( askRevertDlg );
  3882.         ::ModalDialog( GetODButtonKeyFilterProc(), &btnClicked );
  3883.         ::DisposeDialog( askRevertDlg );
  3884.     }
  3885.     CATCH_ALL
  3886.     {
  3887.         btnClicked = kSHLscCancel;        // Cancel the revert
  3888.     }
  3889.     ENDTRY;
  3890.  
  3891.     fWindowState->ActivateFrontWindows(fEV);
  3892.  
  3893.     EndUsingLibraryResources(savedRefNum);;
  3894.     return kSHLscOK == btnClicked;
  3895. }
  3896.  
  3897.  
  3898. //-------------------------------------------------------------------------------------
  3899. // Drafts
  3900. //-------------------------------------------------------------------------------------
  3901. #ifdef _USE_DIALOGS_LIB_
  3902. #ifdef __cplusplus
  3903. extern "C" {
  3904. #endif
  3905. typedef ODError (*DraftWindowEntry)( Environment* ev, ODSession* session,
  3906.         ODWindowState* winState, ODDocument* document );
  3907. #ifdef __cplusplus
  3908. }
  3909. #endif
  3910.  
  3911. OSErr LoadODSharedLibrary( Str63 libName, Str255 entryName,
  3912.         CFragConnectionID* connID, void** entryPoint );
  3913. void UnloadODSharedLibrary( CFragConnectionID* connID );
  3914.  
  3915. #endif
  3916. void    RealShell::Drafts(ODDocument* document)
  3917. {
  3918. #ifdef _USE_DIALOGS_LIB_
  3919.     DraftWindowEntry dwi = kODNULL;
  3920.     CFragConnectionID connID ;
  3921.     THROW_IF_ERROR( LoadODSharedLibrary( "\pDialogsLib",
  3922.             "\pDraftWindowEntry", &connID, (void**)&dwi ) );
  3923.     THROW_IF_ERROR( (*dwi)( fEV, fSession, fWindowState, document ) );
  3924.     UnloadODSharedLibrary( &connID );
  3925.     return;
  3926. #else
  3927.     ODDraft* topDraft = ODGetTempDraftFromOpenDocument(fEV, fSession, document);
  3928.     if (topDraft)
  3929.         topDraft->Acquire(fEV);
  3930.     else
  3931.         topDraft = document->AcquireDraft(fEV,kODDPReadOnly,0,kODNULL,kODPosTop,kODFalse);
  3932.     
  3933.     DraftWindow* d = new DraftWindow;
  3934.     DraftWinAction     dWinAction = kDraftWinNone;
  3935.     ODDraft*    curDraft = kODNULL;
  3936.     d->InitDraftWindow(fEV, topDraft);
  3937.  
  3938.     fWindowState->DeactivateFrontWindows(fEV);
  3939.     ArrowCursor();
  3940.     do {
  3941.         dWinAction = d->Drafts(fEV, curDraft, dWinAction, ODDraftHasWriteAccess(fEV, topDraft));
  3942.         switch (dWinAction) {
  3943.             case kDraftWinCreate:
  3944.                 WASSERT(ODDraftHasWriteAccess(fEV, topDraft));
  3945.                 fWindowState->ActivateFrontWindows(fEV);
  3946.                 d->DraftSaved(fEV, topDraft);
  3947.                 ODSaveDocument(fEV, fSession, document);
  3948.                 ODCloseDraft(fEV, fSession, topDraft);
  3949. #ifdef ODDebug
  3950.                 ODULong topDraftRefCount = topDraft->GetRefCount(fEV);
  3951.                 WASSERT(topDraftRefCount == 2);
  3952. #endif
  3953.                 topDraft->Release(fEV); // to balance the CreateDraft when the document was opened
  3954.                 topDraft = document->CreateDraft(fEV, topDraft, kODTrue);
  3955.                     // This CreateDraft call is doing two things with refcounts.
  3956.                     // First, it is releasing topDraft which balances the Acquire at the top of
  3957.                     // this function.
  3958.                     // Second, it is creating a new temp draft, which puts us in the same
  3959.                     // state as we were before the above topDraft->Release, except
  3960.                     // for the need to Reacquire the topDraft as was done at the top of this 
  3961.                     // function which we do in the next statement.
  3962.                 topDraft->Acquire(fEV);
  3963.                 
  3964.                 ODTempDraftCreated(fEV, fSession, document, topDraft);
  3965.                 curDraft = topDraft;
  3966.  
  3967.                 {
  3968.                 TempODStorageUnit su = topDraft->AcquireDraftProperties(fEV);
  3969.                 ODResetDateModByInfo(fEV, su);    
  3970.                 }
  3971.                 
  3972.                 d->InitDraftWindow(fEV, topDraft);
  3973.                 ODOpenDraft(fEV, fSession, topDraft);
  3974.                 ODSaveDocument(fEV, fSession, document);
  3975.                 fWindowState->DeactivateFrontWindows(fEV);
  3976.                 
  3977.                 break;
  3978.             case kDraftWinDelete:
  3979.                 ODDraft* selDraft = d->GetSelectedDraft();
  3980.  
  3981.                 ODCloseDraft(fEV, fSession, selDraft);
  3982.                 ODReleaseObject( fEV, selDraft );    // -- TÇ: was acquired in draftswindow
  3983.  
  3984.                 d->DeleteSelectedDraft(fEV, fSession); 
  3985.                 break;
  3986.         }
  3987.     } while (dWinAction == kDraftWinDelete);
  3988.  
  3989.     fWindowState->ActivateFrontWindows(fEV);
  3990.     
  3991.     if (dWinAction == kDraftWinOpen)
  3992.     {
  3993.         // open selected Drafts as additional root windows within this process
  3994.         // if a particular draft already has a window, bring it to front, don't create a new one
  3995.         ODDraft* selDraft = d->GetSelectedDraft();
  3996.         WASSERT(selDraft);
  3997.         
  3998.         ODOpenDraft(fEV, fSession, selDraft);
  3999.     }
  4000.     ODDeleteObject(d);
  4001.     ODReleaseObject( fEV, topDraft );    // balances Acquire & AcquireDraft at beginning.
  4002.  
  4003.     if ( dWinAction == kDraftWinLowMemAbort )
  4004.         THROW( kODErrOutOfMemory );
  4005. #endif
  4006. }
  4007.  
  4008. //-------------------------------------------------------------------------------------
  4009. // Info
  4010. //-------------------------------------------------------------------------------------
  4011.  
  4012.  
  4013. void    RealShell::DocumentInfo(ODDocument* document)
  4014. {
  4015.     ODUnused(document);
  4016.     
  4017.     ODDocumentInfo(fEV, fSession);
  4018. }
  4019.  
  4020. /*
  4021. // Default implementation for active parts which do nothing.  Keep this code -TÇ.
  4022. void    RealShell::PartInfo()
  4023. {
  4024.     ArrowCursor();
  4025.     ODTypeToken selectionFocus = fSession->Tokenize(fEV, kODSelectionFocus);
  4026.     TempODFrame activeFrame = fSession->GetArbitrator(fEV)->AcquireFocusOwner(fEV, selectionFocus);
  4027.     ODFrameFacetIterator* facets = activeFrame->CreateFacetIterator(fEV);
  4028.     fSession->GetInfo(fEV)->ShowPartFrameInfo(fEV, facets->First(fEV),
  4029.         this->HasWriteAccess());
  4030.     ODDeleteObject(facets);
  4031. }
  4032. */
  4033.  
  4034. //-------------------------------------------------------------------------------------
  4035. // Error Handling
  4036. //-------------------------------------------------------------------------------------
  4037.  
  4038. void    RealShell::ExceptionAlert(ODError exceptionCode, const char message[])
  4039. {
  4040.     Str255 errStr;
  4041.  
  4042.     gODDelayBentoFatalError = gODSuppressBentoFatalError = kODFalse;
  4043.     if ( gODBentoFatalErrorHasOccurred )
  4044.         ODBentoFatalError(/*allowSuppress*/ kODFalse);
  4045.     
  4046.     // Errors not to display:
  4047.     if( exceptionCode == kODNoError || exceptionCode == kODErrAlreadyNotified
  4048.                                     || exceptionCode == userCanceledErr )
  4049.         return;
  4050.  
  4051.     // If interaction is allowed, notify user until process is activated:
  4052.     if( AEInteractWithUser(kNoTimeOut,kODNULL,kODNULL) != noErr )
  4053.         return;
  4054.     
  4055.     TRY{
  4056.     
  4057.         CUsingLibraryResources r;
  4058.  
  4059.         ODBoolean lowMem = ! this->CheckFreeMemory();
  4060.     
  4061.         TRY{
  4062.             if (fWindowState)
  4063.                 fWindowState->DeactivateFrontWindows(fEV);
  4064.         }CATCH_ALL{
  4065.             WARN("Error %d deactivating front windows",ErrorCode());
  4066.             // don't reraise
  4067.         }ENDTRY
  4068.         
  4069.         LookupErrString(exceptionCode, kODErrUserID, errStr);
  4070.         if ( fFailedPlugInName[0] != 0 )
  4071.         {
  4072.             ReplaceIntoString( kSHLPlugInErrorStrID, fFailedPlugInName, errStr, errStr);
  4073.             fFailedPlugInName[0] = 0;
  4074.         }
  4075.     
  4076.     #if ODDebug
  4077.         ParamText(errStr, "\pOption-click OK for more…", kODEmptyPString, kODEmptyPString);
  4078.             // NOTE: This hard coded string is ok because it is for debugging only. -TC
  4079.     #else
  4080.         ParamText(errStr, kODEmptyPString, kODEmptyPString, kODEmptyPString);
  4081.     #endif
  4082.     
  4083.         // Do not use a filter-proc if low on memory since it calls back to OpenDoc!
  4084.         ModalFilterUPP filter = lowMem ?kODNULL :GetODButtonKeyFilterProc();
  4085.     
  4086.     
  4087.         // Shazam! Show the alert:
  4088.         ShowAlert(fEV, kSHLphGenError, filter, fSession);
  4089.     
  4090.         TRY{
  4091.             if (IsOptionKeyDown()) 
  4092.             {
  4093.                 Str255    debugStrString;
  4094.                 debugStrString[0] = 0;
  4095.                 
  4096.                 GetIndString(debugStrString, kSHLStrsID, kSHLStrIndDException);
  4097.                 
  4098.                 Str255    tempString;
  4099.         
  4100.                 NumToString(exceptionCode, tempString);
  4101.                 if (debugStrString[0] + tempString[0] <= 255)
  4102.                     ConcatPascalStrings(debugStrString, tempString);
  4103.         
  4104.                 LookupErrString(exceptionCode, kODErrSupportID, errStr);
  4105.                 
  4106.                 char msg[256];
  4107.                 if( message ) {
  4108.                     strncpy(msg,message,255);
  4109.                     msg[255] = 0;
  4110.                     c2pstr(msg);
  4111.                 } else
  4112.                     msg[0] = 0;
  4113.                 
  4114.                 ParamText(errStr, debugStrString, (StringPtr)msg, kODEmptyPString);
  4115.                 ShowAlert(fEV, kSHLphGenError, filter, fSession);
  4116.             }
  4117.         }CATCH_ALL{
  4118.             WARN("Error %d handling opt key down",ErrorCode());
  4119.             // don't reraise
  4120.         }ENDTRY
  4121.         
  4122.     #ifdef SHLTestErrorDialogUsage
  4123.         SHLDebugStr("\pPostErrorDialog HeapInfo…");
  4124.         HeapInfo();
  4125.     #endif
  4126.             
  4127.         TRY{
  4128.             if (fWindowState)
  4129.                 fWindowState->ActivateFrontWindows(fEV);
  4130.         }CATCH_ALL{
  4131.             WARN("Error %d re-activating front windows",ErrorCode());
  4132.             // don't reraise
  4133.         }ENDTRY
  4134.     
  4135.         ResetAlertStage();
  4136.         
  4137.     }CATCH_ALL{
  4138.         SysBeep(3);
  4139.         WARN("Error %d thrown by exception alert",ErrorCode());
  4140.         // Eat exception, don't reraise
  4141.     }ENDTRY
  4142.  
  4143.     gODDelayBentoFatalError = gODSuppressBentoFatalError = kODFalse;
  4144.     if ( gODBentoFatalErrorHasOccurred )
  4145.         ODBentoFatalError(/*allowSuppress*/ kODFalse);
  4146. }
  4147.  
  4148. //----------------------------------------------------------------------------------------
  4149. // SearchErrTable: Private function
  4150. //----------------------------------------------------------------------------------------
  4151.  
  4152. ODBoolean RealShell::SearchErrTable(ODError value,
  4153.                               ODResNumber resourceID,
  4154.                               Str255 str)
  4155. {
  4156.     ErrRecordHandle table;
  4157.  
  4158.     str[0] = 0;
  4159.     ODSLong        savedRefNum;
  4160.     BeginUsingLibraryResources(savedRefNum);
  4161.     table = (ErrRecordHandle)GetResource('errs', resourceID);
  4162.     DetachResource((Handle)table);
  4163.     EndUsingLibraryResources(savedRefNum);
  4164.     
  4165.     if (table)
  4166.     {
  4167.         short lenTab;
  4168.         ODResNumber strID = 0;
  4169.         SignedByte savedState = HGetState((Handle)table);
  4170.         HLock((Handle)table);
  4171.         
  4172.         ErrRecordPointer pEntry = *table;
  4173.  
  4174.         lenTab = (short)(GetHandleSize((Handle)table) / sizeof(ErrRecord));
  4175.         for (short i = 1; i <= lenTab; ++i, ++pEntry)
  4176.         {
  4177.             if (pEntry->lowErr == 0)
  4178.                 strID = (ODResNumber)(pEntry->index);    // WARNING: assigning an ODULong to a short
  4179.             else if ((pEntry->lowErr <= value) && (value <= pEntry->highErr))
  4180.             {
  4181.                 if (pEntry->index > 0)
  4182.                 {
  4183.                     ODSLong        savedRefNum;
  4184.                     BeginUsingLibraryResources(savedRefNum);
  4185.                     GetIndString(str, strID, (ODResNumber)(pEntry->index)); // WARNING: passing in an ODULong as a short
  4186.                     EndUsingLibraryResources(savedRefNum);;
  4187.                 }
  4188.                 return kODTrue;
  4189.             }
  4190.         }
  4191.         HSetState((Handle)table, savedState);
  4192.     }
  4193.     return kODFalse;
  4194. } // SearchErrTable 
  4195.  
  4196. //----------------------------------------------------------------------------------------
  4197. // LookupErrString: 
  4198. //----------------------------------------------------------------------------------------
  4199.  
  4200. ODBoolean RealShell::LookupErrString(ODError value,
  4201.                                ODResNumber resourceID,
  4202.                                Str255 str)
  4203. {
  4204.     if (SearchErrTable(value, 0/*errAppTable*/ + resourceID, str))
  4205.         return kODTrue;
  4206.     else
  4207.         return SearchErrTable(value, resourceID, str);
  4208. } // LookupErrString 
  4209.  
  4210. //----------------------------------------------------------------------------------------
  4211. // CreateDefaultIText: 
  4212. //
  4213. // <eeh> this might be more useful in IText.cpp or whatever it's called.
  4214. //----------------------------------------------------------------------------------------
  4215.  
  4216. static ODIText* CreateDefaultIText(StringPtr text)
  4217. {
  4218.     ODScriptCode script = FontToScript( GetSysFont() );;
  4219.     ODLangCode lang = GetScriptVariable(script, smScriptLang);
  4220.     return CreateITextPString( script, lang, text);
  4221. }
  4222.  
  4223. /*********************************************************************************
  4224. SendFinderODOCEvent
  4225. Temporary function that should be merged with Jens's CreateFinderRevealEvent in
  4226. WinPopM.cpp (UI subsystem).  Or perhaps we needn't bother, since this is just
  4227. a workaround anyway.
  4228. *********************************************************************************/
  4229.  
  4230. static OSErr SendFinderODOCEvent( const FSSpec *fileToOpen )
  4231. {
  4232.     const DescType kFinderSignature    = 'MACS';
  4233.  
  4234.     OSErr err;
  4235.     OSType finderSignature = kFinderSignature;
  4236.     AliasHandle alias = NULL;
  4237.     AEDesc target = NULL_DESCRIPTOR_DEFINITION;
  4238.     AEDescList list = NULL_DESCRIPTOR_DEFINITION;
  4239.  
  4240.     AppleEvent openEvent = NULL_DESCRIPTOR_DEFINITION;
  4241.     
  4242.     err= AECreateDesc(typeApplSignature,&finderSignature,sizeof(OSType), &target);
  4243.     if( err ) goto exit;
  4244.     err= AECreateAppleEvent( kCoreEventClass, kAEOpenDocuments, &target,
  4245.             kAutoGenerateReturnID, kAnyTransactionID, &openEvent );
  4246.     if( err ) goto exit;
  4247. //    AEDisposeDesc(&target);
  4248.     err= NewAliasMinimal( fileToOpen, &alias );
  4249.     if( err ) goto exit;
  4250.  
  4251.     err= AECreateList(NULL,0,false, &list);
  4252.     if( err ) goto exit;
  4253.     err= AEPutPtr(&list,1,typeAlias,*alias,GetHandleSize((Handle)alias));
  4254.     if( err ) goto exit;
  4255.     
  4256.     err= AEPutParamDesc(&openEvent, keyDirectObject, &list);
  4257.     if( err ) goto exit;
  4258.  
  4259.     err = AESend( &openEvent, kODNULL,
  4260.             kAENoReply|kAEAlwaysInteract|kAECanSwitchLayer,
  4261.             kAENormalPriority, kNoTimeOut, kODNULL, kODNULL );
  4262.  
  4263.     if (err == connectionInvalid)
  4264.         FinderNotRunning();
  4265.  
  4266. exit:
  4267.     AEDisposeDesc(&target);
  4268.     AEDisposeDesc(&list);
  4269.     if( alias ) DisposeHandle((Handle)alias);
  4270. //    if( err )
  4271.         AEDisposeDesc(&openEvent);
  4272.     
  4273.     return err;
  4274. }
  4275.  
  4276. //------------------------------------------------------------------------------
  4277. // FinderNotRunning
  4278. //------------------------------------------------------------------------------
  4279.  
  4280. void FinderNotRunning()
  4281. {
  4282.     StopAlert(kODAlertShellFinderNotRunning, (ModalFilterUPP)NULL);
  4283. }
  4284.  
  4285. //------------------------------------------------------------------------------
  4286. // ReportErrorGeneric
  4287. //------------------------------------------------------------------------------
  4288.  
  4289. void ReportErrorGeneric(StringPtr errorString)
  4290. {
  4291.     ReportErrorSimple(errorString);
  4292. }
  4293.  
  4294.