MacTech Network:   MacForge.net  |  Computer Memory  |  Register Domains  |  Printer Supplies  |  Cables  |  iPod Deals  |  Mac Deals  |  Mac Book Shelf


  MacTech Magazine

The journal of Macintosh technology

 
 
HASP SRM

Magazine In Print
  About MacTech  
  Home Page  
  Subscribe  
  Archives DVD  
  Submit News  
  Submit a Tip!  
  Get a copy of MacTech RISK FREE  
Google
Entire Web
mactech.com
Mac Community
More...
MacTech Central
  by Category  
  by Company  
  by Product  
MacTech News
  MacTech News  
  Previous News  
  MacTech RSS  
Article Archives
  Show Indices  
  by Volume  
  by Author  
  Source Code FTP  
Inside MacTech
  Writer's Kit  
  Editorial Staff  
  Editorial Calendar  
  Back Issues  
  Advertising  
Contact Us
  Customer Service  
  MacTech Store  
  Legal/Disclaimers  
  Webmaster Feedback  

Demonstration Program

Go to Contents
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// Files2.h
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
//
// This program demonstrates:
//
// ¥  The use of Navigation Services rather than the Standard File Package to display
//    Open, Save, and Choose a Folder dialog boxes.
//
// ¥  The use of Navigation Services rather than the Dialog Manager to display Save
//    Changes and Discard Changes alert boxes.
//
// ¥  Application-defined file handling functions associated with:
//
//    ¥    The user invoking the File menu Open., Close, Save, Save As., Revert to Saved,
//        and Quit commands of a typical application.
//
//    ¥    Handling of the required Apple events Open Application, Re-open Application,
//        Open Documents and Quit Application.
//
//    These functions are essentially the same as those in the demonstration program
//    Files1 except that the safe-save methodology used in Files1 is not used, all
//    saves being direct to the target file.
//
// To keep the code not specifically related to files and file-handling to a minimum, an 
// item is included in the Demonstration menu which allows the user to simulate 
// "touching" a window (that is, modifying the contents of the associated document).  
// Choosing the first menu item in this menu sets the window-touched flag in the window's
// document structure to true and draws the text "WINDOW TOUCHED" in the window in a 
// large font size, this latter so that the user can keep track of which windows have
// been "touched".
//
// This program is also, in part, an extension of the demonstration program Windows2 in
// that it also demonstrates certain file-related Window Manager features introduced with
// the Mac OS 8.5 Window Manager.  These features are:
//
// ¥  Window proxy icons.
//
// ¥  Window path pop-up menus.
//
// Those sections of the source code relating to these features is identified with /////
// at the right of each line.
//
// The program utilises the following resources:
//
// ¥  An 'MBAR' resource, and 'MENU' resources for Apple, File, Edit and Demonstration
//    menus (preload, non-purgeable).  
//
// ¥  A 'WIND' resource (purgeable) (initially not visible).  
//
// ¥  A 'STR ' resource containing the "missing application name" string, which is copied
//    to all document files created by the program.
//
// ¥  'STR#' resources (purgeable) containing error strings, the application's name (for
//    certain Navigation Services functions), and a message  string for the Choose a 
//    Folder dialog box.
//      
// ¥  A 'kind' resource (purgeable) describing file types, which is used by Navigation 
//    Services to  build the native file types section of the Show pop-up menu in the 
//    Open dialog box.
//
// ¥  An 'open' resource (purgeable) containing the file type list for the Open dialog
//    box.
//
// ¥  A 'pnot' and associated 'PICT' resource (both purgeable), which provide the preview
//    for the PICT file.
//
// ¥  The 'BNDL' resource (non-purgeable), 'FREF' resources (non-purgeable), signature
//    resource (non-purgeable), and icon family resources (purgeable), required to 
//    support the built application.
//
// ¥  A 'SIZE' resource with the acceptSuspendResumeEvents, isHighLevelEventAware, and
//    is32BitCompatible flags set (non-purgeable).    
//
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

// ............................................................................. includes

#include <Appearance.h>
#include <AERegistry.h>
#include <Devices.h>
#include <Folders.h>
#include <Gestalt.h>                                                                /////
#include <Navigation.h>
#include <Resources.h>
#include <Sound.h>
#include <ToolUtils.h>

// ............................................................................. typedefs

typedef struct
{
  TEHandle    editStrucHdl;
  PicHandle   pictureHdl;
  SInt16      fileRefNum;
  FSSpec      fileFSSpec;
  AliasHandle aliasHdl;                                                             /////
  Boolean     windowTouched;
}  docStructure, *docStructurePointer, **docStructureHandle;

typedef StandardFileReply *standardFileReplyPtr;

// .............................................................................. defines

#define mApple                  128
#define  iAbout                 1
#define mFile                   129
#define  iNew                   1
#define  iOpen                  2
#define  iClose                 4
#define  iSave                  5
#define  iSaveAs                6
#define  iRevert                7
#define  iQuit                  12
#define mDemonstration          131
#define  iTouchWindow           1
#define  iChooseAFolderDialog   3
#define rNewWindow              128
#define rMenubar                128
#define rRevertAlert            128
#define rCloseFileAlert         129
#define rCustomOpenDialog       130
#define  iPopupItem             10
#define rSelectDirectoryDialog  131
#define  iSelectButton          10
#define rErrorStrings           128  
#define  eInstallHandler        1000
#define  eMaxWindows            1001
#define  eFileIsOpen            opWrErr
#define  eNoNavServices         1002
#define  eCantFindFinderProcess 1003                                                /////
#define rMiscStrings            129
#define  sApplicationName       1
#define  sChooseAFolder         2
#define rOpenResource           128
#define kMaxWindows             10
#define MAXLONG                 0x7FFFFFFF
#define MIN(a,b)                ((a) < (b) ? (a) : (b))

// .................................................................. function prototypes

void      main                  (void);
void      eventLoop             (void);
void      doInitManagers        (void);
void      doInstallAEHandlers   (void);
void      doEvents              (EventRecord *);
void      doMouseDown           (EventRecord *);
void      doBringFinderToFront  (void);                                             /////
OSErr     doFindProcess        (OSType,OSType,ProcessSerialNumber *);               /////
void      doUpdate              (EventRecord *);
void      doMenuChoice          (SInt32);
void      doFileMenu            (SInt16);
void      doAdjustMenus         (void);
void      doErrorAlert          (SInt16);
void      doCopyPString         (Str255,Str255);
void      doConcatPStrings      (Str255,Str255);
void      doTouchWindow         (void);
void      doSynchroniseFiles    (void);                                             /////
pascal OSErr  doOpenAppEvent          (AppleEvent *,AppleEvent *,SInt32);
pascal OSErr  doReopenAppEvent        (AppleEvent *,AppleEvent *,SInt32);
pascal OSErr  doOpenDocsEvent         (AppleEvent *,AppleEvent *,SInt32);
pascal OSErr  doQuitAppEvent          (AppleEvent *,AppleEvent *,SInt32);
OSErr         doHasGotRequiredParams  (AppleEvent *);

OSErr  doNewCommand            (void);
OSErr  doOpenCommand           (void);
OSErr  doCloseCommand          (NavAskSaveChangesAction);
OSErr  doSaveCommand           (void);
OSErr  doSaveAsCommand         (void);
OSErr  doRevertCommand         (void);
OSErr  doQuitCommand           (NavAskSaveChangesAction);
OSErr  doNewDocWindow          (Boolean,OSType);
OSErr  doOpenFile              (FSSpec,OSType);
OSErr  doReadTextFile          (WindowPtr);
OSErr  doReadPictFile          (WindowPtr);
OSErr  doCloseFile             (WindowPtr,docStructureHandle,NavAskSaveChangesAction);
OSErr  doWriteFile             (WindowPtr,Boolean);
OSErr  doWriteTextData         (WindowPtr,SInt16);
OSErr  doWritePictData         (WindowPtr,SInt16);
OSErr  doCopyResources         (WindowPtr);
OSErr  doCopyAResource         (ResType,SInt16,SInt16,SInt16);
pascal void navEventFunction   (NavEventCallbackMessage,NavCBRecPtr,NavCallBackUserData);

OSErr  doChooseAFolderDialog  (FSSpec *);

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// Files2.c
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

// ............................................................................. includes

#include "Files2.h"

// ..................................................................... global variables

Boolean           gMacOS85Present  = false;                                         /////
Boolean           gDone;
Boolean           gInBackground;
AEEventHandlerUPP doOpenAppEventUPP;
AEEventHandlerUPP doReopenAppEventUPP;
AEEventHandlerUPP doOpenDocsEventUPP;
AEEventHandlerUPP doQuitAppEventUPP;
SInt16            gAppResFileRefNum;

extern SInt16     gCurrentNumberOfWindows;
extern Rect       gDestRect,gViewRect;

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× main

void  main(void)
{
  OSErr       osError;                                                              /////
  SInt32      response;                                                             /////
  Handle      menubarHdl;
  MenuHandle  menuHdl;

  // .................................................................initialise managers

  doInitManagers();

  // ....................................... check whether Mac OS 8.5 or later is present

  osError = Gestalt(gestaltSystemVersion,&response);                                /////
                                                                                    /////
  if(osError == noErr && response >= 0x00000850)                                    /////
    gMacOS85Present = true;                                                         /////

  // ............................. check for Navigation Services, and pre-load (optional)

  if(NavServicesAvailable())
    NavLoad();
  else
    doErrorAlert(eNoNavServices);

  // ................................. create routine decriptors for Apple event handlers

  doOpenAppEventUPP    = NewAEEventHandlerProc((ProcPtr) doOpenAppEvent);
  doReopenAppEventUPP  = NewAEEventHandlerProc((ProcPtr) doReopenAppEvent);
  doOpenDocsEventUPP   = NewAEEventHandlerProc((ProcPtr) doOpenDocsEvent);
  doQuitAppEventUPP    = NewAEEventHandlerProc((ProcPtr) doQuitAppEvent);

  // ........................... set application's resource fork as current resource file

  gAppResFileRefNum = CurResFile();

  // .......................................................... set up menu bar and menus
  
  menubarHdl = GetNewMBar(rMenubar);
  if(menubarHdl == NULL)
    doErrorAlert(MemError());
  SetMenuBar(menubarHdl);
  DrawMenuBar();

  menuHdl = GetMenuHandle(mApple);
  if(menuHdl == NULL)
    doErrorAlert(MemError());
  else
    AppendResMenu(menuHdl,'DRVR');

  // .............................................. install required Apple event handlers

  doInstallAEHandlers();
  
  // ................................................................... enter event loop

  eventLoop();
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× eventLoop

void  eventLoop(void)
{
  EventRecord eventStructure;

  gDone = false;

  while(!gDone)
  {
    if(WaitNextEvent(everyEvent,&eventStructure,MAXLONG,NULL))
      doEvents(&eventStructure);
#if TARGET_CPU_PPC                                                                  /////
    else                                                                            /////
      if(gMacOS85Present)                                                           /////
        doSynchroniseFiles();                                                       /////
#endif                                                                              /////
  }
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doInitManagers

void  doInitManagers(void)
{
  MaxApplZone();
  MoreMasters();

  InitGraf(&qd.thePort);
  InitFonts();
  InitWindows();
  InitMenus();
  TEInit();
  InitDialogs(NULL);

  InitCursor();
  FlushEvents(everyEvent,0);

  RegisterAppearanceClient();
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doInstallAEHandlers

void  doInstallAEHandlers(void)
{
  OSErr  osError;

  osError = AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,doOpenAppEventUPP,
                                  0L,false);
  if(osError != noErr)  doErrorAlert(eInstallHandler);

  osError = AEInstallEventHandler(kCoreEventClass,kAEReopenApplication,
                                  doReopenAppEventUPP,0L,false);
  if(osError != noErr)  doErrorAlert(eInstallHandler);

  osError = AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,doOpenDocsEventUPP,
                                  0L,false);
  if(osError != noErr)  doErrorAlert(eInstallHandler);

  osError = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,doQuitAppEventUPP,
                                  0L,false);
  if(osError != noErr)  doErrorAlert(eInstallHandler);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doEvents

void  doEvents(EventRecord *eventStrucPtr)
{
  SInt8  charCode;

  switch(eventStrucPtr->what)
  {
    case kHighLevelEvent:
      AEProcessAppleEvent(eventStrucPtr);
      break;

    case mouseDown:
      doMouseDown(eventStrucPtr);
      break;

    case keyDown:
    case autoKey:
      charCode = eventStrucPtr->message & charCodeMask;
      if((eventStrucPtr->modifiers & cmdKey) != 0)
      {
        doAdjustMenus();
        doMenuChoice(MenuEvent(eventStrucPtr));
      }
      break;

    case updateEvt:
      doUpdate(eventStrucPtr);
      break;

    case osEvt:
      switch((eventStrucPtr->message >> 24) & 0x000000FF)
      {
        case suspendResumeMessage:
          gInBackground = (eventStrucPtr->message & resumeFlag) == 0;
          break;
      }
      HiliteMenu(0);
      break;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMouseDown

void  doMouseDown(EventRecord *eventStrucPtr)
{
  WindowPtr windowPtr;
  SInt16    partCode;
  OSStatus  osStatus;                                                               /////
  Boolean   handled = false;                                                        /////
  SInt32    itemSelected;                                                           /////
      
  partCode = FindWindow(eventStrucPtr->where,&windowPtr);
  
  switch(partCode)
  {
    case inMenuBar:
      doAdjustMenus();
      doMenuChoice(MenuSelect(eventStrucPtr->where));
      break;

    case inContent:
      if(windowPtr != FrontWindow())
        SelectWindow(windowPtr);
      break;

    case inGoAway:
      if(TrackGoAway(windowPtr,eventStrucPtr->where) == true)
        doCloseCommand(kNavSaveChangesClosingDocument);
      break;

#if TARGET_CPU_PPC                                                                  /////
    case inProxyIcon:                                                               /////
      osStatus = TrackWindowProxyDrag(windowPtr,eventStrucPtr->where);              /////
      if(osStatus == errUserWantsToDragWindow)                                      /////
        handled = false;                                                            /////
      else if(osStatus == noErr)                                                    /////
        handled = true;                                                             /////
#endif                                                                              /////

    case inDrag:                                                                    /////
#if TARGET_CPU_PPC                                                                  /////
      if(gMacOS85Present)                                                           /////
      {                                                                             /////
        if(!handled)                                                                /////
        {                                                                           /////
          if(IsWindowPathSelectClick(windowPtr,eventStrucPtr))                      /////
          {                                                                         /////
            if(WindowPathSelect(windowPtr,NULL,&itemSelected) == noErr)             /////
            {                                                                       /////
              if(LoWord(itemSelected) > 1)                                          /////
                doBringFinderToFront();                                             /////
            }                                                                       /////
                                                                                    /////
            handled = true;                                                         /////
          }                                                                         /////
        }                                                                           /////
        if(!handled)                                                                /////
          DragWindow(windowPtr,eventStrucPtr->where,&qd.screenBits.bounds);         /////
      }                                                                             /////
      else                                                                          /////
#endif                                                                              /////
        DragWindow(windowPtr,eventStrucPtr->where,&qd.screenBits.bounds);
      break;
  }
}

#if TARGET_CPU_PPC                                                                  /////
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doBringFinderToFront

void  doBringFinderToFront(void)                                                    /////
{                                                                                   /////
  ProcessSerialNumber  finderProcess;                                               /////
                                                                                    /////
  if(doFindProcess('MACS','FNDR',&finderProcess) == noErr)                          /////
    SetFrontProcess(&finderProcess);                                                /////
  else                                                                              /////
    doErrorAlert(eCantFindFinderProcess);                                           /////
}                                                                                   /////

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doFindProcess

OSErr  doFindProcess(OSType creator,OSType type,ProcessSerialNumber *outProcSerNo)
{                                                                                   /////
  ProcessSerialNumber procSerialNo;                                                 /////
  ProcessInfoRec      procInfoStruc;                                                /////
  OSErr               osError = 0;                                                  /////
                                                                                    /////
  procSerialNo.highLongOfPSN = 0;                                                   /////
  procSerialNo.lowLongOfPSN   = kNoProcess;                                         /////
                                                                                    /////
  procInfoStruc.processInfoLength  = sizeof(ProcessInfoRec);                        /////
  procInfoStruc.processName        = NULL;                                          /////
  procInfoStruc.processAppSpec    = NULL;                                           /////
  procInfoStruc.processLocation    = NULL;                                          /////
                                                                                    /////
  while(true)                                                                       /////
  {                                                                                 /////
    osError = GetNextProcess(&procSerialNo);                                        /////
    if(osError != noErr)                                                            /////
      break;                                                                        /////
                                                                                    /////
    osError = GetProcessInformation(&procSerialNo,&procInfoStruc);                  /////
    if(osError != noErr)                                                            /////
      break;                                                                        /////
    if((procInfoStruc.processSignature == creator) &&                               /////
       (procInfoStruc.processType == type))                                         /////
      break;                                                                        /////
  }                                                                                 /////
                                                                                    /////
  *outProcSerNo = procSerialNo;                                                     /////
                                                                                    /////  
  return osError;                                                                   /////
}                                                                                   /////
#endif                                                                              /////

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doUpdate

void  doUpdate(EventRecord *eventStrucPtr)
{
  WindowPtr           windowPtr;
  docStructureHandle  docStrucHdl;
  GrafPtr             oldPort;
  Rect                destRect;

  windowPtr = (WindowPtr) eventStrucPtr->message;
  docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);

  GetPort(&oldPort);
  SetPort(windowPtr);

  BeginUpdate(windowPtr);

  if((*docStrucHdl)->pictureHdl)
  {
    destRect = (*(*docStrucHdl)->pictureHdl)->picFrame;
    OffsetRect(&destRect,170,54);
    HLock((Handle) (*docStrucHdl)->pictureHdl);
    DrawPicture((*docStrucHdl)->pictureHdl,&destRect);
    HUnlock((Handle) (*docStrucHdl)->pictureHdl);
  }
  else if((*docStrucHdl)->editStrucHdl)
  {
    HLock((Handle) (*docStrucHdl)->editStrucHdl);
    TEUpdate(&gDestRect,(*docStrucHdl)->editStrucHdl);
    HUnlock((Handle) (*docStrucHdl)->editStrucHdl);
  }

  if((*docStrucHdl)->windowTouched)
  {
    TextSize(48);
    MoveTo(30,170);
    DrawString("\pWINDOW TOUCHED");
    TextSize(12);
  }

  EndUpdate((WindowPtr)eventStrucPtr->message);

  SetPort(oldPort);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMenuChoice

void  doMenuChoice(SInt32 menuChoice)
{
  SInt16  menuID, menuItem;
  Str255  itemName;
  SInt16  daDriverRefNum;
  OSErr   osError;
  FSSpec  fileSpec;
  Rect    theRect;
  Str255  theString, numberString;  

  menuID = HiWord(menuChoice);
  menuItem = LoWord(menuChoice);

  if(menuID == 0)
    return;

  switch(menuID)
  {
    case mApple:
      GetMenuItemText(GetMenuHandle(mApple),menuItem,itemName);
      daDriverRefNum = OpenDeskAcc(itemName);
      break;

    case mFile:
      doFileMenu(menuItem);
      break;

    case mDemonstration:
      if(menuItem == iTouchWindow)
        doTouchWindow();
      else if(menuItem == iChooseAFolderDialog)
      {
        if((osError = doChooseAFolderDialog(&fileSpec)) && osError != userCanceledErr)
          doErrorAlert(osError);
        else
        {
          if(FrontWindow())
          {
            SetPort(FrontWindow());
            TextSize(10);
            SetRect(&theRect,0,271,600,300);
            EraseRect(&theRect);
            if(osError != userCanceledErr)
            {
              doCopyPString(fileSpec.name,theString);
              doConcatPStrings(theString, "\p   Volume Reference Number: ");
              NumToString((SInt32) fileSpec.vRefNum,numberString);
              doConcatPStrings(theString,numberString);
              doConcatPStrings(theString, "\p   Parent Directory ID: ");
              NumToString((SInt32) fileSpec.parID,numberString);
              doConcatPStrings(theString,numberString);
              MoveTo(10,290);
              DrawString(theString);
            }
          }
        }
      }
      break;
  }

  HiliteMenu(0);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doFileMenu

void  doFileMenu(SInt16 menuItem)
{
  OSErr  osError;
  
  switch(menuItem)
  {
    case iNew:
      if(osError = doNewCommand())
        doErrorAlert(osError);
      break;

    case iOpen:
      if(osError = doOpenCommand())
        doErrorAlert(osError);
      break;

    case iClose:
      if((osError = doCloseCommand(kNavSaveChangesClosingDocument)) && 
          osError != kNavAskSaveChangesCancel)
        doErrorAlert(osError);
      break;

    case iSave:
      if(osError = doSaveCommand())
        doErrorAlert(osError);
      break;

    case iSaveAs:
      if(osError = doSaveAsCommand())
        doErrorAlert(osError);
      break;

    case iRevert:
      if(osError = doRevertCommand())
        doErrorAlert(osError);
      break;

    case iQuit:
      if((osError = doQuitCommand(kNavSaveChangesQuittingApplication)) && 
          osError != kNavAskSaveChangesCancel)
        doErrorAlert(osError);
      if(osError != kNavAskSaveChangesCancel)
      {
        NavUnload();
        gDone = true;
      }
      break;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doAdjustMenus

void  doAdjustMenus(void)
{
  MenuHandle          menuHdl;
  WindowPtr           windowPtr;
  docStructureHandle  docStrucHdl;

  windowPtr = FrontWindow();
  docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);

  menuHdl = GetMenuHandle(mFile);

  if(gCurrentNumberOfWindows > 0)
  {
    menuHdl = GetMenuHandle(mFile);
    EnableItem(menuHdl,iClose);
    if((*docStrucHdl)->windowTouched)
    {
      EnableItem(menuHdl,iSave);
      EnableItem(menuHdl,iRevert);
    }
    else
    {
      DisableItem(menuHdl,iSave);
      DisableItem(menuHdl,iRevert);
    }
    EnableItem(menuHdl,iSaveAs);

    menuHdl = GetMenuHandle(mDemonstration);
    if((*docStrucHdl)->windowTouched == false)
      EnableItem(menuHdl,iTouchWindow);
    else
      DisableItem(menuHdl,iTouchWindow);
  }
  else
  {
    menuHdl = GetMenuHandle(mFile);
    DisableItem(menuHdl,iClose);
    DisableItem(menuHdl,iSave);
    DisableItem(menuHdl,iSaveAs);
    DisableItem(menuHdl,iRevert);
    menuHdl = GetMenuHandle(mDemonstration);
    DisableItem(menuHdl,iTouchWindow);
  }  

  DrawMenuBar();
}
  
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doErrorAlert

void  doErrorAlert(SInt16 errorCode)
{
  AlertStdAlertParamRec paramRec;
  Str255                errorString, theString;
  SInt16                itemHit;

  paramRec.movable        = true;
  paramRec.helpButton     = false;
  paramRec.filterProc     = NULL;
  paramRec.defaultText    = (StringPtr) kAlertDefaultOKText;
  paramRec.cancelText     = NULL;
  paramRec.otherText      = NULL;
  paramRec.defaultButton  = kAlertStdAlertOKButton;
  paramRec.cancelButton   = 0;
  paramRec.position       = kWindowDefaultPosition;

  if(errorCode == eInstallHandler)
    GetIndString(errorString,rErrorStrings,1);
  else if(errorCode == eMaxWindows)
    GetIndString(errorString,rErrorStrings,2);
  else if(errorCode == eFileIsOpen)
    GetIndString(errorString,rErrorStrings,3);
  else if(errorCode == eNoNavServices)
    GetIndString(errorString,rErrorStrings,4);
  else if(errorCode == eCantFindFinderProcess)
    GetIndString(errorString,rErrorStrings,5);
  else
  {
    GetIndString(errorString,rErrorStrings,6);
    NumToString((SInt32) errorCode,theString);
    doConcatPStrings(errorString,theString);
  }

  if(errorCode != memFullErr && errorCode != eNoNavServices)
    StandardAlert(kAlertCautionAlert,errorString,NULL,¶mRec,&itemHit);
  else
  {
    StandardAlert(kAlertStopAlert,errorString,NULL,¶mRec,&itemHit);
    ExitToShell();
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCopyPString

void  doCopyPString(Str255 sourceString,Str255 destinationString)
{
  SInt16  stringLength;

  stringLength = sourceString[0];
  BlockMove(sourceString + 1,destinationString + 1,stringLength);
  destinationString[0] = stringLength;
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doConcatPStrings

void  doConcatPStrings(Str255 targetString,Str255 appendString)
{
  SInt16  appendLength;

  appendLength = MIN(appendString[0],255 - targetString[0]);

  if(appendLength > 0)
  {
    BlockMoveData(appendString+1,targetString+targetString[0]+1,(SInt32) appendLength);
    targetString[0] += appendLength;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doTouchWindow

void  doTouchWindow(void)
{
  WindowPtr           windowPtr;
  docStructureHandle  docStrucHdl;

  windowPtr = FrontWindow();
  docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
  
  SetPort(windowPtr);
  
  TextSize(48);
  MoveTo(30,170);
  DrawString("\pWINDOW TOUCHED");
  TextSize(12);

  (*docStrucHdl)->windowTouched = true;

#if TARGET_CPU_PPC                                                                  /////
  if(gMacOS85Present)                                                               /////
    SetWindowModified(windowPtr,true);                                              /////
#endif                                                                              /////
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doSynchroniseFiles

#if TARGET_CPU_PPC                                                                  /////
void  doSynchroniseFiles(void)                                                      /////
{                                                                                   /////
  UInt32              currentTicks;                                                 /////
  WindowPtr            windowPtr;                                                   /////
  SInt16              trashVRefNum;                                                 /////
  SInt32              trashDirID;                                                   /////
  static UInt32       nextSynchTicks = 0;                                           /////
  docStructureHandle  docStrucHdl;                                                  /////
  Boolean             aliasChanged;                                                 /////
  AliasHandle         aliasHdl;                                                     /////
  FSSpec              newFSSpec;                                                    /////
  OSErr               osError;                                                      /////
                                                                                    /////
  currentTicks = TickCount();                                                       /////
  windowPtr     = FrontNonFloatingWindow();                                         /////
                                                                                    /////
  if(currentTicks > nextSynchTicks)                                                 /////
  {                                                                                 /////
    while(windowPtr != NULL)                                                        /////
    {                                                                               /////
      docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);                     /////
                                                                                    /////
      if(docStrucHdl != NULL)                                                       /////
      {                                                                             /////
        if((*docStrucHdl)->aliasHdl == NULL)                                        /////
          break;                                                                    /////
                                                                                    /////
        aliasChanged = false;                                                       /////
        aliasHdl = (*docStrucHdl)->aliasHdl;                                        /////
        ResolveAlias(NULL,aliasHdl,&newFSSpec,&aliasChanged);                       /////
                                                                                    /////
        if(aliasChanged)                                                            /////
        {                                                                           /////
          (*docStrucHdl)->fileFSSpec = newFSSpec;                                   /////
          SetWTitle(windowPtr,newFSSpec.name);                                      /////
        }                                                                           /////
                                                                                    /////
        osError = FindFolder(kOnSystemDisk,kTrashFolderType,kDontCreateFolder,      /////
                             &trashVRefNum,&trashDirID);                            /////
                                                                                    /////
        if(osError == noErr)                                                        /////
        {                                                                           /////
          do                                                                        /////
          {                                                                         /////
            if(newFSSpec.parID == fsRtParID)                                        /////
              break;                                                                /////
                                                                                    /////
            if((newFSSpec.vRefNum == trashVRefNum) && (newFSSpec.parID == trashDirID))
            {                                                                       /////
              FSClose((*docStrucHdl)->fileRefNum);                                  /////
              if((*docStrucHdl)->editStrucHdl)                                      /////
                TEDispose((*docStrucHdl)->editStrucHdl);                            /////
              if((*docStrucHdl)->pictureHdl)                                        /////
                KillPicture((*docStrucHdl)->pictureHdl);                            /////
              DisposeHandle((Handle) docStrucHdl);                                  /////
              DisposeWindow(windowPtr);                                             /////
              gCurrentNumberOfWindows --;                                           /////
              break;                                                                /////
            }                                                                       /////
          } while(FSMakeFSSpec(newFSSpec.vRefNum,newFSSpec.parID,"\p",&newFSSpec) == noErr);
        }                                                                           /////
      }                                                                             /////
                                                                                    /////  
      windowPtr = GetNextWindow(windowPtr);                                         /////
    }                                                                               /////
                                                                                    /////
    nextSynchTicks = currentTicks + 15;                                             /////
  }                                                                                 /////
}                                                                                   /////
#endif                                                                              /////

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doOpenAppEvent

pascal OSErr  doOpenAppEvent(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefCon)
{
  OSErr  osError;

  osError = doHasGotRequiredParams(appEvent);
  if(osError == noErr)
    osError = doNewCommand();

  return(osError);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doReopenAppEvent

pascal OSErr  doReopenAppEvent(AppleEvent *appEvent,AppleEvent *reply,
                               SInt32 handlerRefCon)
{
  OSErr  osError;

  osError = doHasGotRequiredParams(appEvent);
  if(osError == noErr)
    if(!FrontWindow())
      osError = doNewCommand();

  return(osError);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doOpenDocsEvent

pascal OSErr  doOpenDocsEvent(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefcon)
{
  FSSpec      fileSpec;
  AEDescList  docList;
  OSErr       osError, ignoreErr;
  SInt32      index, numberOfItems;
  Size        actualSize;
  AEKeyword   keyWord;
  DescType    returnedType;
  FInfo       fileInfo;

  osError = AEGetParamDesc(appEvent,keyDirectObject,typeAEList,&docList);

  if(osError == noErr)
  {
    osError = doHasGotRequiredParams(appEvent);
    if(osError == noErr)
    {
      AECountItems(&docList,&numberOfItems);
      if(osError == noErr)
      {
        for(index=1;index<=numberOfItems;index++)
        {
          osError = AEGetNthPtr(&docList,index,typeFSS,&keyWord,&returnedType,
                              (Ptr) &fileSpec,sizeof(fileSpec),&actualSize);
          if(osError == noErr)
          {
            osError = FSpGetFInfo(&fileSpec,&fileInfo);
            if(osError == noErr)
            {
              if(osError = doOpenFile(fileSpec,fileInfo.fdType))
                doErrorAlert(osError);
            }
          }
          else
            doErrorAlert(osError);
        }
      }
    }
    else
      doErrorAlert(osError);

    ignoreErr = AEDisposeDesc(&docList);
  }
  else
    doErrorAlert(osError);

  return(osError);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doQuitAppEvent

pascal OSErr  doQuitAppEvent(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefcon)
{
  OSErr  osError;

  osError = doHasGotRequiredParams(appEvent);
  if(osError == noErr)
  {
    while(FrontWindow())
    {
      osError = doCloseCommand(kNavSaveChangesQuittingApplication);

      if(osError != noErr && osError != kNavAskSaveChangesCancel)
        doErrorAlert(osError);
      if(osError == kNavAskSaveChangesCancel)
        return;
    }
  }

  NavUnload();
  gDone = true;

  return(osError);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doHasGotRequiredParams

OSErr  doHasGotRequiredParams(AppleEvent *appEvent)
{
  DescType  returnedType;
  Size      actualSize;
  OSErr     osError;

  osError = AEGetAttributePtr(appEvent,keyMissedKeywordAttr,typeWildCard,&returnedType,
                            NULL,0,&actualSize);
  if(osError == errAEDescNotFound)
    return(noErr);
  else if(osError == noErr)
    return(errAEParamMissed);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// NewOpenCloseSave.c
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

// ............................................................................. includes

#include "Files2.h"

// ..................................................................... global variables

WindowPtr   gWindowPtr;
SInt16      gCurrentNumberOfWindows = 0;
Rect        gDestRect,gViewRect;

extern SInt16   gAppResFileRefNum;
extern Boolean  gMacOS85Present;                                                    /////

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doNewCommand

OSErr  doNewCommand(void)
{
  OSErr   osError;
  OSType  documentType = 'TEXT';

  osError = doNewDocWindow(true,documentType);

#if TARGET_CPU_PPC                                                                  /////
  if(gMacOS85Present)                                                               /////
  {                                                                                 /////
    if(osError == noErr)                                                            /////
      SetWindowProxyCreatorAndType(gWindowPtr,'kBkB','TEXT',kOnSystemDisk);         /////
  }                                                                                 /////
#endif                                                                              /////

  return(osError);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doOpenCommand

OSErr  doOpenCommand(void)
{  
  NavDialogOptions    dialogOptions;
  NavTypeListHandle   fileTypeListHdl = NULL;
  NavEventUPP         navEventFunctionUPP;
  OSErr               osError = noErr;
  NavReplyRecord      navReplyStruc;
  AEDesc              resultDesc;
  SInt32              index, count;
  FSSpec              fileSpec;  
  FInfo               fileInfo;
  OSType              documentType;
  
  NavGetDefaultDialogOptions(&dialogOptions);

  GetIndString((unsigned char*) &dialogOptions.clientName,rMiscStrings,sApplicationName);
  fileTypeListHdl = (NavTypeListHandle) GetResource('open',rOpenResource);

  navEventFunctionUPP = NewNavEventProc((ProcPtr) navEventFunction);

  osError = NavGetFile(NULL,&navReplyStruc,&dialogOptions,navEventFunctionUPP,NULL,NULL,
                     fileTypeListHdl,0);

  DisposeRoutineDescriptor(navEventFunctionUPP);

  if(navReplyStruc.validRecord && osError == noErr)
  {
    if(osError == noErr)
    {
      osError = AECountItems(&(navReplyStruc.selection),&count);

      for(index=1;index<=count;index++)
      {
        resultDesc.dataHandle = 0L;

        if((osError = AEGetNthDesc(&(navReplyStruc.selection),index,typeFSS,NULL,
           &resultDesc)) == noErr)
        {
          BlockMoveData(*resultDesc.dataHandle,&fileSpec,sizeof(FSSpec));

          if((osError = FSpGetFInfo(&fileSpec,&fileInfo)) == noErr)
          {
            documentType = fileInfo.fdType;
            
            osError = doOpenFile(fileSpec,documentType);
          }

          AEDisposeDesc(&resultDesc);
        }
      }
    }
    
    NavDisposeReply(&navReplyStruc);  
  }

  if(fileTypeListHdl != NULL)
    ReleaseResource((Handle) fileTypeListHdl);

  if(osError == userCanceledErr)
    osError = noErr;
    
  return(osError);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCloseCommand

OSErr  doCloseCommand(NavAskSaveChangesAction action)
{
  WindowPtr           windowPtr;
  SInt16              windowKind;
  docStructureHandle  docStrucHdl;
  OSErr               osError = noErr;

  windowPtr = FrontWindow();
  windowKind = ((WindowPeek) windowPtr)->windowKind;

  switch(windowKind)
  {
    case kApplicationWindowKind:
      docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
  
      osError = doCloseFile(windowPtr,docStrucHdl,action);

      if(osError == kNavAskSaveChangesCancel)
        return(kNavAskSaveChangesCancel);
      else if(osError == noErr)
      {
        DisposeWindow(windowPtr);
        gCurrentNumberOfWindows --;
      }
      break;
      
    case kDialogWindowKind:
      // Hide or close modeless dialog, as required.
      break;
  }

  return(osError);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doSaveCommand

OSErr  doSaveCommand(void)
{
  WindowPtr            windowPtr;
  docStructureHandle  docStrucHdl;
  OSErr                osError = noErr;
  
  windowPtr = FrontWindow();
  docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);

  if((*docStrucHdl)->fileRefNum)
  {
    osError = doWriteFile(windowPtr,false);

    SetPort(windowPtr);
    EraseRect(&windowPtr->portRect);
    InvalRect(&windowPtr->portRect);
  }    
  else
    osError = doSaveAsCommand();

#if TARGET_CPU_PPC                                                                  /////
  if(gMacOS85Present)                                                               /////
  {                                                                                 /////
    if(osError == noErr)                                                            /////
      SetWindowModified(windowPtr,false);                                           /////
  }                                                                                 /////
#endif                                                                              /////
  
  return(osError);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doSaveAsCommand

OSErr  doSaveAsCommand(void)
{
  NavDialogOptions    dialogOptions;
  WindowPtr           windowPtr;
  docStructureHandle  docStrucHdl;
  NavEventUPP         navEventFunctionUPP;
  OSType              fileType;
  OSErr               osError = noErr;
  NavReplyRecord      navReplyStruc;
  AEDesc              resultDesc;  
  FSSpec              fileSpec;  
  SInt16              fileRefNum;

  NavGetDefaultDialogOptions(&dialogOptions);

  windowPtr = FrontWindow();

  docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
  GetWTitle(windowPtr,dialogOptions.savedFileName);
  GetIndString((unsigned char*) &dialogOptions.clientName,rMiscStrings,sApplicationName);
  
  navEventFunctionUPP = NewNavEventProc((ProcPtr) navEventFunction);
      
  if((*docStrucHdl)->editStrucHdl)
    fileType = 'TEXT';
  else if((*docStrucHdl)->pictureHdl)
    fileType = 'PICT';

  osError = NavPutFile(NULL,&navReplyStruc,&dialogOptions,navEventFunctionUPP,
                       fileType,'kBkB',NULL);

  DisposeRoutineDescriptor(navEventFunctionUPP);

  if(navReplyStruc.validRecord && osError == noErr)
  {
    resultDesc.dataHandle = 0L;

    if((osError = AEGetNthDesc(&(navReplyStruc.selection),1,typeFSS,NULL,&resultDesc)) 
       == noErr)
    {
      BlockMoveData(*resultDesc.dataHandle,&fileSpec,sizeof(FSSpec));

      if(!navReplyStruc.replacing)
      {
        osError = FSpCreate(&fileSpec,'kBkB',fileType,navReplyStruc.keyScript);
        if(osError != noErr)
        {
          AEDisposeDesc(&resultDesc);
          NavDisposeReply(&navReplyStruc);
          return(osError);
        }
      }
        
      (*docStrucHdl)->fileFSSpec = fileSpec;

      if((*docStrucHdl)->fileRefNum != 0)
      {
        osError = FSClose((*docStrucHdl)->fileRefNum);
        (*docStrucHdl)->fileRefNum = 0;
      }
      
      if(osError == noErr)
        osError = FSpOpenDF(&(*docStrucHdl)->fileFSSpec,fsRdWrPerm,&fileRefNum);

      if(osError == noErr)
      {
        (*docStrucHdl)->fileRefNum = fileRefNum;
        SetWTitle(windowPtr,fileSpec.name);
        
#if TARGET_CPU_PPC                                                                  /////
        if(gMacOS85Present)                                                         /////
        {                                                                           /////
          SetPort(windowPtr);                                                       /////
          SetWindowProxyFSSpec(windowPtr,&fileSpec);                                /////
          GetWindowProxyAlias(windowPtr,&((*docStrucHdl)->aliasHdl));               /////
          SetWindowModified(windowPtr,false);                                       /////
        }                                                                           /////
#endif                                                                              /////
        
        osError = doWriteFile(windowPtr,!navReplyStruc.replacing);
      }

      AEDisposeDesc(&resultDesc);
      NavCompleteSave(&navReplyStruc,kNavTranslateInPlace);
    }

    NavDisposeReply(&navReplyStruc);
  }

  SetPort(windowPtr);
  EraseRect(&windowPtr->portRect);
  InvalRect(&windowPtr->portRect);

  if(osError == userCanceledErr)
    osError = noErr;
  
  return(osError);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doRevertCommand

OSErr  doRevertCommand(void)
{
  NavEventUPP             navEventFunctionUPP;
  WindowPtr               windowPtr;
  docStructureHandle      docStrucHdl;
  Str255                  fileName;
  NavDialogOptions        dialogOptions;
  NavAskSaveChangesResult reply;
  OSErr                   osError = noErr;
  
  navEventFunctionUPP = NewNavEventProc((ProcPtr) navEventFunction);

  windowPtr = FrontWindow();
  docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
  
  SetPort(windowPtr);

  GetWTitle(windowPtr,fileName);
  BlockMoveData(fileName,dialogOptions.savedFileName,fileName[1]);

  osError = NavAskDiscardChanges(&dialogOptions,&reply,navEventFunctionUPP,0);

  if(reply == kNavAskDiscardChanges)
  {
    EraseRect(&windowPtr->portRect);
    
    if((*docStrucHdl)->editStrucHdl)
    {
      osError = doReadTextFile(windowPtr);
    }
    else if((*docStrucHdl)->pictureHdl)
    {
      KillPicture((*docStrucHdl)->pictureHdl);
      (*docStrucHdl)->pictureHdl = NULL;
      
      osError = doReadPictFile(windowPtr);
    }

    (*docStrucHdl)->windowTouched = false;

#if TARGET_CPU_PPC                                                                  /////
    if(gMacOS85Present)                                                             /////
      SetWindowModified(windowPtr,false);                                           /////
#endif                                                                              /////
    
    InvalRect(&windowPtr->portRect);
  }

  return(osError);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doQuitCommand

OSErr  doQuitCommand(NavAskSaveChangesAction action)
{
  OSErr  osError = noErr;

  while(FrontWindow())
  {
    osError = doCloseCommand(action);
    if(osError != noErr)
      return(osError);
  }

  return(osError);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doNewDocWindow

OSErr  doNewDocWindow(Boolean showWindow,OSType documentType)
{
  docStructureHandle  docStrucHdl;

  if(gCurrentNumberOfWindows == kMaxWindows)
    return(eMaxWindows);

  if(!(gWindowPtr = GetNewCWindow(rNewWindow,NULL,(WindowPtr)-1)))
    return(MemError());

  SetPort(gWindowPtr);

  if(!(docStrucHdl = (docStructureHandle) NewHandle(sizeof(docStructure))))
  {
    DisposeWindow(gWindowPtr);
    return(MemError());
  }

  SetWRefCon(gWindowPtr,(SInt32) docStrucHdl);

  (*docStrucHdl)->editStrucHdl  = NULL;
  (*docStrucHdl)->pictureHdl    = NULL;
  (*docStrucHdl)->fileRefNum    = 0;
  (*docStrucHdl)->windowTouched  = false;
  (*docStrucHdl)->aliasHdl      = NULL;                                             /////

  if(documentType == 'TEXT')
  {
    gDestRect = gWindowPtr->portRect;
    InsetRect(&gDestRect,6,6);
    gViewRect = gDestRect;

    MoveHHi((Handle) docStrucHdl);
    HLock((Handle) docStrucHdl);

    if(!((*docStrucHdl)->editStrucHdl = TENew(&gDestRect,&gViewRect)))
    {
      DisposeWindow(gWindowPtr);
      DisposeHandle((Handle) docStrucHdl);
      return(MemError());
    }

    HUnlock((Handle) docStrucHdl);
  }

  if(showWindow)
    ShowWindow(gWindowPtr);

  gCurrentNumberOfWindows ++;

  return(noErr);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doOpenFile

OSErr  doOpenFile(FSSpec fileSpec,OSType documentType)
{
  OSErr               osError;
  SInt16              fileRefNum;
  docStructureHandle  docStrucHdl;

  if(osError = doNewDocWindow(false,documentType))
    return(osError);

  SetWTitle(gWindowPtr,fileSpec.name);  

  if(osError = FSpOpenDF(&fileSpec,fsRdWrPerm,&fileRefNum))
  {
    DisposeWindow(gWindowPtr);
    gCurrentNumberOfWindows --;
    return(osError);
  }
  
  docStrucHdl = (docStructureHandle) GetWRefCon(gWindowPtr);
  (*docStrucHdl)->fileRefNum = fileRefNum;
  (*docStrucHdl)->fileFSSpec = fileSpec;

  if(documentType == 'TEXT')
  {
    if(osError = doReadTextFile(gWindowPtr))
      return(osError);
  }
  else if(documentType == 'PICT')
  {
    if(osError = doReadPictFile(gWindowPtr))
      return(osError);
  }

#if TARGET_CPU_PPC                                                                  /////
  if(gMacOS85Present)                                                               /////
  {                                                                                 /////
    SetWindowProxyFSSpec(gWindowPtr,&fileSpec);                                     /////
    GetWindowProxyAlias(gWindowPtr,&((*docStrucHdl)->aliasHdl));                    /////
    SetWindowModified(gWindowPtr,false);                                            /////
  }                                                                                 /////
#endif                                                                              /////

  ShowWindow(gWindowPtr);

  return(noErr);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCloseFile

OSErr  doCloseFile(WindowPtr windowPtr,docStructureHandle docStrucHdl,
                   NavAskSaveChangesAction action)
{
  NavAskSaveChangesResult reply = 0;
  NavEventUPP             navEventFunctionUPP;
  NavDialogOptions        dialogOptions;
  Str255                  fileName;
  OSErr                   osError;

  if((*docStrucHdl)->windowTouched)
  {
    GetWTitle(windowPtr,fileName);
    BlockMoveData(fileName,dialogOptions.savedFileName,fileName[0]+1);

    navEventFunctionUPP = NewNavEventProc((ProcPtr) navEventFunction);

    osError = NavAskSaveChanges(&dialogOptions,action,&reply,navEventFunctionUPP,0);

    DisposeRoutineDescriptor(navEventFunctionUPP);
  
    if(reply == kNavAskSaveChangesCancel)
      return((OSErr) reply);
    else if(reply == kNavAskSaveChangesSave)
    {
      if(osError = doSaveCommand())
        return(osError);
    }
  }

  if((*docStrucHdl)->fileRefNum != 0)
  {
    if(!(osError = FSClose((*docStrucHdl)->fileRefNum)))  
    {
      osError = FlushVol(NULL,(*docStrucHdl)->fileFSSpec.vRefNum);
      (*docStrucHdl)->fileRefNum = 0;
    }
  }

  if((*docStrucHdl)->editStrucHdl)
    TEDispose((*docStrucHdl)->editStrucHdl);
  if((*docStrucHdl)->pictureHdl)
    KillPicture((*docStrucHdl)->pictureHdl);

  DisposeHandle((Handle) docStrucHdl);
  
  return(osError);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doWriteFile

OSErr  doWriteFile(WindowPtr windowPtr,Boolean newFile)
{
  docStructureHandle  docStrucHdl;
  OSErr               osError;
  SInt32              fileRefNum;
  
  docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
  fileRefNum = (*docStrucHdl)->fileRefNum;

  if((*docStrucHdl)->editStrucHdl)
    osError = doWriteTextData(windowPtr,fileRefNum);
  else if((*docStrucHdl)->pictureHdl)
    osError = doWritePictData(windowPtr,fileRefNum);

  if(osError == noErr)
    if(newFile)
      osError = doCopyResources(windowPtr);

  return(osError);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doReadTextFile

OSErr  doReadTextFile(WindowPtr windowPtr)
{
  docStructureHandle  docStrucHdl;
  SInt16              fileRefNum;
  TEHandle            textEditHdl;
  SInt32              numberOfBytes;
  Handle              textBuffer;
  OSErr               osError;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
  fileRefNum = (*docStrucHdl)->fileRefNum;

  textEditHdl = (*docStrucHdl)->editStrucHdl;
  (*textEditHdl)->txSize = 10;
  (*textEditHdl)->lineHeight = 15;

  SetFPos(fileRefNum,fsFromStart,0);
  GetEOF(fileRefNum,&numberOfBytes);

  if(numberOfBytes > 32767)
    numberOfBytes = 32767;

  if(!(textBuffer = NewHandle((Size) numberOfBytes)))
    return(MemError());

  osError = FSRead(fileRefNum,&numberOfBytes,*textBuffer);
  if(osError == noErr || osError == eofErr)
  {
    MoveHHi(textBuffer);
    HLockHi(textBuffer);
    TESetText(*textBuffer,numberOfBytes,(*docStrucHdl)->editStrucHdl);
    HUnlock(textBuffer);
    DisposeHandle(textBuffer);
  }
  else
    return(osError);

  return(noErr);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doReadPictFile

OSErr  doReadPictFile(WindowPtr windowPtr)
{
  docStructureHandle  docStrucHdl;
  SInt16              fileRefNum;
  SInt32              numberOfBytes;
  OSErr               osError;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
  fileRefNum = (*docStrucHdl)->fileRefNum;

  GetEOF(fileRefNum,&numberOfBytes);
  SetFPos(fileRefNum,fsFromStart,512);
  numberOfBytes -= 512;

  if(!((*docStrucHdl)->pictureHdl = (PicHandle) NewHandle(numberOfBytes)))
    return(MemError());

  osError = FSRead(fileRefNum,&numberOfBytes,*(*docStrucHdl)->pictureHdl);
  if(osError == noErr || osError == eofErr)
    return(noErr);
  else
    return(osError);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doWriteTextData

OSErr  doWriteTextData(WindowPtr windowPtr,SInt16 tempFileRefNum)
{
  docStructureHandle  docStrucHdl;
  TEHandle            textEditHdl;
  Handle              editText;
  SInt32              numberOfBytes;
  SInt16              volRefNum;
  OSErr               osError;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
  textEditHdl = (*docStrucHdl)->editStrucHdl;
  editText = (*textEditHdl)->hText;
  numberOfBytes = (*textEditHdl)->teLength;

  osError = SetFPos(tempFileRefNum,fsFromStart,0);
  if(osError == noErr)
    osError = FSWrite(tempFileRefNum,&numberOfBytes,*editText);
  if(osError == noErr)
    osError = SetEOF(tempFileRefNum,numberOfBytes);
  if(osError == noErr)
    osError = GetVRefNum(tempFileRefNum,&volRefNum);
  if(osError == noErr)
    osError = FlushVol(NULL,volRefNum);

  if(osError == noErr)
    (*docStrucHdl)->windowTouched = false;

  return(osError);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doWritePictData

OSErr  doWritePictData(WindowPtr windowPtr,SInt16 tempFileRefNum)
{
  docStructureHandle  docStrucHdl;
  PicHandle           pictureHdl;
  SInt32              numberOfBytes, dummyData;
  SInt16              volRefNum;
  OSErr               osError;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);
  pictureHdl = (*docStrucHdl)->pictureHdl;

  numberOfBytes = 512;
  dummyData = 0;

  osError = SetFPos(tempFileRefNum,fsFromStart,0);

  if(osError == noErr)
    osError = FSWrite(tempFileRefNum,&numberOfBytes,&dummyData);

  numberOfBytes = GetHandleSize((Handle) (*docStrucHdl)->pictureHdl);

  if(osError == noErr)
  {
    HLock((Handle) (*docStrucHdl)->pictureHdl);
    osError = FSWrite(tempFileRefNum,&numberOfBytes,*(*docStrucHdl)->pictureHdl);
    HUnlock((Handle) (*docStrucHdl)->pictureHdl);
  }

  if(osError == noErr)
    osError = SetEOF(tempFileRefNum,512 + numberOfBytes);
  if(osError == noErr)
    osError = GetVRefNum(tempFileRefNum,&volRefNum);
  if(osError == noErr)
    osError = FlushVol(NULL,volRefNum);

  if(osError == noErr)
    (*docStrucHdl)->windowTouched = false;

  return(osError);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCopyResources

OSErr  doCopyResources(WindowPtr windowPtr)
{
  docStructureHandle  docStrucHdl;
  OSType              fileType;
  OSErr               osError;
  SInt16              fileRefNum;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowPtr);

  if((*docStrucHdl)->editStrucHdl)
    fileType = 'TEXT';
  else if((*docStrucHdl)->pictureHdl)
    fileType = 'PICT';

  FSpCreateResFile(&(*docStrucHdl)->fileFSSpec,'kBkB',fileType,smSystemScript);

  osError = ResError();
  if(osError == noErr)
    fileRefNum = FSpOpenResFile(&(*docStrucHdl)->fileFSSpec,fsRdWrPerm);

  if(fileRefNum > 0)
  {
    osError = doCopyAResource('STR ',-16396,gAppResFileRefNum,fileRefNum);
    
    if(fileType == 'PICT')
    {
      doCopyAResource('pnot',128,gAppResFileRefNum,fileRefNum);
      doCopyAResource('PICT',128,gAppResFileRefNum,fileRefNum);
    }
  }
  else
    osError = ResError();

  if(osError == noErr)
    CloseResFile(fileRefNum); 

  osError = ResError();
  return(osError);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCopyAResource

OSErr  doCopyAResource(ResType resourceType,SInt16 resourceID,SInt16 sourceFileRefNum,
                      SInt16 destFileRefNum)
{
  Handle  sourceResourceHdl;
  Str255  sourceResourceName;
  ResType ignoredType;
  SInt16  ignoredID;

  UseResFile(sourceFileRefNum);

  sourceResourceHdl = GetResource(resourceType,resourceID);

  if(sourceResourceHdl != NULL)
  {
    GetResInfo(sourceResourceHdl,&ignoredID,&ignoredType,sourceResourceName);
    DetachResource(sourceResourceHdl);
    UseResFile(destFileRefNum);
    AddResource(sourceResourceHdl,resourceType,resourceID,sourceResourceName);
    if(ResError() == noErr)
      UpdateResFile(destFileRefNum);
  }

  ReleaseResource(sourceResourceHdl);

  return(ResError());
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× navEventFunction

pascal void navEventFunction(NavEventCallbackMessage callBackSelector, 
                             NavCBRecPtr callBackParms,NavCallBackUserData callBackUD)
{
  WindowPtr  windowPtr;
  
  windowPtr = (WindowPtr) callBackParms->eventData.eventDataParms.event->message;

  switch(callBackSelector)
  {
    case kNavCBEvent:
      switch(callBackParms->eventData.eventDataParms.event->what)
      {
        case updateEvt:
          if(((WindowPeek) windowPtr)->windowKind != kDialogWindowKind)
            doUpdate((EventRecord *) callBackParms->eventData.eventDataParms.event);
          break;
      }
      break;
  } 
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// ChooseAFolderDialog.c
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

// ............................................................................. includes

#include "Files2.h"

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doChooseAFolderDialog

OSErr  doChooseAFolderDialog(FSSpec *theFileSpec)
{  
  NavDialogOptions  dialogOptions;
  NavEventUPP       navEventFunctionUPP;
  OSErr             osError;
  NavReplyRecord    navReplyStruc;
  FSSpec            fileSpec;  
  AEDesc            resultDesc;
  
  osError = NavGetDefaultDialogOptions(&dialogOptions);
  GetIndString(dialogOptions.message,rMiscStrings,sChooseAFolder);

  navEventFunctionUPP = NewNavEventProc((ProcPtr) navEventFunction);
  
  osError = NavChooseFolder(NULL,&navReplyStruc,&dialogOptions,navEventFunctionUPP,NULL,0);

  DisposeRoutineDescriptor(navEventFunctionUPP);

  if((navReplyStruc.validRecord) && (osError == noErr))
  {
    if((osError = AECoerceDesc(&(navReplyStruc.selection),typeFSS,&resultDesc)) == noErr)
    {
      BlockMoveData(*resultDesc.dataHandle,&fileSpec,sizeof(FSSpec));
  
      FSMakeFSSpec(fileSpec.vRefNum,fileSpec.parID,fileSpec.name,theFileSpec);
    }
  
    AEDisposeDesc(&resultDesc);
    NavDisposeReply(&navReplyStruc);
  }

  return(osError);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

Demonstration Program Comments

Note 1: Navigation Services requires Mac OS 7.5.do5 or later and Appearance Manager
1.0.1 or later.  The Navigation Services shared library must be installed in the 
Extensions folder.  On 680x0 systems, OpenTransportLib68K 1.3 or later must be installed
in the Extensions folder.

Note 2:  In addition to demonstrating Navigation Services, this program also demonstrates 
window proxy icons and window path pop-up menus.  (See Chapter 4B - More on Windows - Mac 
OS 8.5 Window Managager.)  Comments pertaining to these aspects of the demonstration 
appear in blue.

When the program is run, the user should:

*   Exercise the File menu by opening the supplied TEXT and PICT files, saving those
    files, saving those files under new names, closing files, opening the new files,
    attempting to open files which are already open, attempting to save files to new
    files with existing names, making open windows "touched" by choosing the first item
    in the Demonstration menu, reverting to the saved versions of files associated with
    "touched" windows, choosing Quit when "touched" and non-" touched" windows are open,
    and so on.

*   Choose, via the Show pop-up menu button, the file types required to be displayed in
    the Open dialog.

*   Choose the Choose a Folder item from the Demonstration menu to display the Choose a
    Folder dialog, and choose a folder using the Choose button at the bottom of the
    dialog.  (The name of the chosen folder will be drawn in the bottom-left corner of
    the front window.)
    
*   With either PICT Document or TEXT Document open:

    *   With the chap16b-demo folder open so that the document's Finder icon is visible,
        drag the window proxy icon to the desktop or to another open folder, noting that
        the Finder icon moves to the latter.  Then choose Touch Window from the
        Demonstration menu to simulate unsaved changes to the document.  Note that the
        proxy icon changes to the disabled state.  Then save the file, proving the 
        correct operation of the file synchronisation function.  Note that, after the 
        save, the window proxy icon changes back to the enabled state.

    *   Command-click the window's title to display the window path pop-up menu, choose 
        a folder from the menu, and note that the Finder is brought to the foreground 
        and the chosen folder opens.

The program may be run from within CodeWarrior to demonstrate responses to the File menu
commands and the Choose a Folder dialog.

The built application, together with the supplied TEXT and PICT files, may be used to
demonstrate the additional aspect of integrating the receipt of required Apple events
with the overall file handling mechanism.  To prove the correct handling of the required
Apple events, the user should:

*   Open the application by double-clicking the application icon, noting that a new
    document window is opened after the application is launched and the Open Application
    event is received.

*   Double click on a document icon, or select one or more document icons and either drag
    those icons to the application icon or choose Open from the Finder's File menu,
    noting that the application is launched and the selected files are opened when the
    Open Documents event is received.

*   Close all windows and double-click the application icon, noting that the application
    responds to the Re-open Application event by opening a new window.

*   With several documents open, some with "touched" windows, choose Restart or Shut Down
    from the Finder's Special menu (thus invoking a Quit Application event), noting that,
    for "touched" windows, the Save Changes alert box is presented asking the user
    whether the file should be saved before the shutdown process proceeds.

Files2.h

#typedef

Each window created by the program will have an associated document structure, accessed
via the window structure's refCon field.  The docStructure structure will be used for
document structures.

The editStrucHdl field will be assigned a handle to a TextEdit edit structure ('TEXT'
files).  The pictureHdl field will be assigned a handle to a Picture structure ('PICT'
files).  The fileRefNum and fileFSSpec fields will be assigned the file reference number
and the file system specification structure of the file associated with the window.  The
windowTouched field will be set to true when a window has been made "touched", that is,
when the associated document in memory has been modified by the user.

When a file is opened, the aliasHdl field will be assigned a handle to a structure of 
type AliasRecord, which contains the alias data for the file.

#define

After the usual constants relating to menus, windows, and alert boxes are established,
additional constants are established a 'STR#' resource containing error strings, four
specific error conditions, a 'STR#' resource containing the application's name and the
message string for the Choose a Folder dialog box, and the 'open' resource containing the
file types list.  kMaxWindows is used to limit the number of windows the user can open.

Files2.c

Files.c is simply the basic "engine" which supports the demonstration.  There is little
in this file which has not featured in previous demonstration programs.

Global Variables

gMacOS85Present will be assigned true if Mac OS 8.5 or later is present.  (Because
window proxy icons and window path pop-up menus are supported only under Mac OS 8.5 or
later, the associated source code will be bypassed if Mac OS 8.5 or later is not 
present.)

gAppResFileRefNum will be assigned the file reference number of the application's
resource fork.

main

The call to Gestalt determines whether Mac OS 8.5 or later is present.

The call to NavServicesAvailable determines whether the Navigation Services shared
library is installed and running on the user's system.  If it is, NavLoad is called to
load the library, otherwise, an error alert is presented and the program terminates. 
(The call to NavLoad is optional.  If the call is not made, the Navigation Services
shared library will not load until your application calls a Navigation Services function,
and will unload after the call completes.  If the NavLoad call is made, you must call the
NavUnload function before quitting so as to release the reserved memory.)

Routine descriptors for the required Apple events (less the Print Documents event) are
created and a call is made to the application-defined function which installs the
handlers.  Also, the file reference number of the application's resource fork (which is
opened automatically at application launch) is assigned to the global variable
gAppResFileRefNum.

EventLoop

If the compilation is for PowerPC (Mac OS 8.5 does not run on 680x0 Macintoshes) and
if Mac OS 8.5 or later is present, the application-defined function doSynchroniseFiles 
is called.  (See File Synchronisation Function at Chapter 4B - More on Windows - Mac OS
8.5 Window Manager.)

doInstallAEHandlers

doInstallAEHandlers installs handlers for the Open Application, Re-Open Application, Open
Documents, and Quit Application events.  (Note that, so as to avoid the necessity to
include application-defined printing functions in this program, a handler for the Print
Documents event is not included in this demonstration.)

doMouseDown

Note that, in the inGoAway case, the constant kNavSaveChangesClosingDocument is passed in
the call to doCloseCommand.  This affects the text in the Save Changes alert box.

The inProxyIcon and inDrag cases recognise that a mouse-down in the proxy icon region can
mean that the user wishes to drag the proxy icon (icon enabled), drag the window (icon 
disabled) or display the window path pop-up menu (Command key down, icon enabled or 
disabled).

If the proxy icon is enabled and the mouse-down is in the proxy icon, 
TrackWindowProxyDrag handles all aspects of the proxy icon drag process while the user 
drags the icon and returns noErr, in which case the local variable handled is assigned 
true and execution drops through to the break at the bottom of the inDrag case.

If TrackWindowProxyDrag returns errUserWantsToDragWindow, the user is either dragging 
the window (proxy icon is disabled) or displaying the window path pop-up menu.  In this 
case, the local variable handled is assigned false and execution falls through to the 
IsWindowPathSelectClick call inside the inDrag case.

IsWindowPathSelectClick reports whether the mouse-down should activate the window path 
pop-up menu.  If this call returns true, WindowPathSelect displays the pop-up menu, 
returning the item selected in the third parameter.  If the menu item chosen is not 
the title of the window itself, the application-defined function doBringFinderToFront 
is called to make the Finder the frontmost process, thus ensuring that the window being 
opened will be visible.  The local variable handled is then set to true so that 
DragWindow will not be called.

If IsWindowPathSelectClick returns false, DragWindow is called to take control of the 
dragging operation.

doBringFinderToFront

doBringFinderToFront is called from the inDrag case in doMouseDown.  It makes the 
Finder the frontmost process.

The call to the application-defined function doFindProcess gets the process serial 
number of the Finder, which is then passed in a call to SetFrontProcess.

doFindProcess

doFindProcess is called by doBringFinderToFront to get the process serial number of 
the Finder.

The first two lines initialise the fields of a process serial number structure so that 
the search starts from kNoProcess.  The next block initialises the fields of a process 
information structure which, amongst other things, contains fields for the signature 
(creator) and file type of the application file.  (The search is for the signature 
(creator) 'MACS' and the type 'FNDR'.)

Within the while loop, GetNextProcess is called to get the process serial number of the 
next process.  The call to GetProcessInformation gets information about this process 
into the process information structure.  The processSignature and processType fields of 
process information structure are then examined.  If they equal 'MACS' and 'FNDR' 
respectively, the while loop exits and the process serial number is assigned to the 
formal parameter outProcSerNo.

doUpdate

doUpdate performs such window updating as is necessary for the satisfactory execution of
the demonstration aspects of the program.

doMenuChoice

If the Choose a Folder item in the Demonstration menu is chosen, the application-defined
function which presents the Choose a Folder dialog box is called.  This function returns
userCanceledErr if the user clicked the Cancel push button in the dialog box.  If an
error other than userCanceledErr is returned, an error alert box is presented and the
else block is bypassed.

The doChooseAFolderDialog function fills in the file system specification structure whose
address is passed in its parameter.  If a window is open, a rectangle in the bottom
corner of the front window is erased and, if the user did not click the Cancel push
button, the chosen folder's name, volume reference number, and parent directory ID are
extracted from the file system specification structure and drawn in the bottom of the
window.

doFileMenu

At the iClose case, kNavSaveChangesClosingDocument is passed in the call to
doCloseCommand.  This affects the wording in the Save Changes alert box.  If
doCloseCommand returns an error, and if that error is not kNavAskSaveChangesCancel (the
user clicked the Cancel push button in the Save Changes alert box), an error alert box is
presented.

At the iQuit case, kNavSaveChangesQuittingApplication is passed in the call to
doQuitCommand.  This affects the wording in the Save Changes alert box.  If doQuitCommand
returns an error, and if that error is not kNavAskSaveChangesCancel (the user clicked the
Cancel push button in the Save Changes alert box), an error alert box is presented.  If
kNavAskSaveChangesCancel was not returned, NavUnload is called to release the memory
reserved for the Navigation Services shared library, and gDone is set to true to cause
program termination. 

doErrorAlert

doErrorAlert handles errors, invoking an appropriate alert box (caution or stop) advising
of the nature of the problem by error code number or straight text.  Note that the program
will only be terminated if the Navigation Services library is not installed and running,
or in the case of the memFullErr error (no more space in the application heap).

doTouchWindow

doTouchWindow is called when the user chooses the Touch Window item in the Demonstration
menu.  Changing the content of the in-memory version of a file is only simulated in this
program.  The text "WINDOW TOUCHED" is drawn in window and the windowTouched field of the
document structure is set to true.

If Mac OS 8.5 is present (meaning that window proxy icons are implemented), 
SetWindowModified is called with true passed in the modified parameter.  This causes 
the proxy icon to appear in the disabled state, indicating that the window has unsaved 
changes.

doSynchroniseFiles

doSynchroniseFiles is called from the main event loop whenever a null event is 
received.  It synchronises the file data for the application's document windows. (See 
File Synchronisation Function at Chapter 4B - More on Windows - Mac OS 8.5 Window 
Manager.)

currentTicks is assigned the number of ticks since system startup.  As will be seen, 
currentTicks will be used to ensure that synchronisations only occur every quarter 
second (15 ticks).  WindowPtr is assigned a pointer to the front non-floating window.

If 15 ticks have elapsed since the last synchronisation, the outer if block executes. 
The while loop walks the window list (see the call to GetNextWindow at the bottom of 
the loop) looking for associated files whose locations have changed.  When the last 
window in the list has been examined, the loop exits.

Within the while loop, GetWRefCon is called to retrieve the handle to the window's 
document structure.

If the aliasHdl field of the window's document structure contains NULL, the window does 
not yet have a file associated with it, in which case execution falls through to the 
next iteration of the while loop and the next window is examined.

If the window has an associated file, the handle to the associated alias structure, 
which contains the alias data for the file, is retrieved.  ResolveAlias is then called 
to perform a search for the target of the alias, returning the file system 
specification for the target file in the third parameter.  After identifying the 
target, ResolveAlias compares some key information about the target with the 
information in the alias structure.  If the information differs, ResolveAlias updates 
the alias structure to match the target and sets the aliasChanged parameter to true.

If the aliasChanged parameter is set to true, meaning that the location of the file has 
changed, the fileFSSpec field of the window's document structure is assigned the file 
system specification structure returned by ResolveAlias.  Since it is also possible 
that the user has renamed the file, SetWTitle is called to set the window's title to 
the filename contained in the name field of the file system specification structure 
returned by ResolveAlias.

The next task is to determine whether the user has moved the file to the trash or to a 
folder in the trash, in which case the document must be closed.  

FindFolder is called to get the volume reference number and parent directory ID of the 
trash folder.

The do/while loop walks up the parent folder hierarchy to the root folder.  At the 
first line in the do/while loop, if the root folder has been reached (fsRtParID is the 
parent ID of the root directory), the file is not in the trash, in which case the loop 
exits at that point.  At the next if statement, the volume reference number and parent 
directory ID of the file are compared with the volume reference number and directory ID 
of the trash.  If they match, the file is closed, its associated memory is disposed of, 
and the window is disposed of.

The bottom line of the do/while loop effects the walk up the parent directory 
hierarchy, FSMakeFSSpec creates a file system specification structure from the current 
contents of the vRefNum and parID fields of newFSSPec.  Since newFSSpec is also the 
target, the parID field is "filled in" again, at every iteration of the loop, with the 
parent ID of the directory passed in the second parameter of the FSMakeFSSpec call.

doOpenAppEvent, doOpenDocsEvent, and doQuitAppEvent

The handlers for the required Apple events are es