SimpleViewer.c

//--------------------------------------------------------------------------------------------
// simple viewer application 
// DEVELOPER SUPPORT May 95
//
// This is a simple viewer application, that illustrates a minimal, but
// functionally complete viewer application.
//
// Nick Thompson, Developer Support, Apple Computer (DEVSUPPORT),
// ©1995, Apple Computer Inc., All Rights Reserved
 
#include <AppleEvents.h>
#include <menus.h>
#include <PictUtils.h>
#include <QDOffScreen.h>
#include <Errors.h>
 
#include "QD3D.h"
#include "QD3DViewer.h"
#include "QD3DGestalt.h"
#include "QD3DViewerGestalt.h"
 
//--------------------------------------------------------------------------------------------
//
const int   kWindowWidth = 220 ;
const int   kWindowHeight = 150 ;
 
//--------------------------------------------------------------------------------------------
//
#define HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
#define LoWrd(aLong)    ((aLong) & 0xFFFF)
 
    
 
//--------------------------------------------------------------------------------------------
// menu id's
enum {
    mApple = 128,
    mFile,
    mEdit
} ;
 
//--------------------------------------------------------------------------------------------
// command id's, Apple menu
enum {
    iAbout = 1
} ;
 
//--------------------------------------------------------------------------------------------
// command id's, File menu
enum {
    iNew = 1,
    iOpen,
    iUnused1,
    iClose,
    iSave,
    iSaveAs,
    iRevert,
    iUnused2,
    iQuit
} ;
 
//--------------------------------------------------------------------------------------------
// command id's, Edit menu
enum {
    iUndo = 1,
    iUnused3,
    iCut,
    iCopy,
    iPaste,
    iClear
} ;
 
//--------------------------------------------------------------------------------------------
// static control variables
 
static Boolean gQuitFlag = false ;              // we ain't quittin yet
static Point gStaggerPos = {50,50} ;            // start opening staggered windows at this point
static AEAddressDesc    gSelfAddress;           // A self-addressed address descriptor record
static ProcessSerialNumber  gSelfPSN;           // This application's psn
 
//--------------------------------------------------------------------------------------------
// function prototypes
 
Boolean SupportsQuickDraw3D(void) ;
Boolean     SupportsQuickDraw3DViewer(void) ;
void        InitToolbox( void ) ;
void        FailIfErr(OSErr something ) ;
void        MainEventLoop( void ) ;
void        HandleKeyPress( EventRecord *event ) ;
Boolean     HandleEvent( EventRecord *theEvent ) ;
void        HandleMenuCommand( long menuResult ) ;
void        MyAdjustMenus( void ) ;
OSErr       MyDisposeViewerWindow( WindowPtr theWindow ) ;
CGrafPtr    MyCreateViewerWindow( void ) ;
 
//-- AppleEvent Related
 
Boolean SupportsAEVT(void) ;
void RegisterMyEvents(void) ;
pascal OSErr MyAEHandleOAPP( AppleEvent *theAppleEvent, AppleEvent *reply, long refCon) ;
pascal OSErr MyAEHandleODOC(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon) ;
pascal OSErr MyAEHandlePDOC(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon) ;
pascal OSErr MyAEHandleQUIT(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon) ;
void DoAppOpenCommand( void ) ;
void MySendQuitApp( void ) ;
void MySendOpenDoc(FSSpec *myFSSpec) ;
 
//--------------------------------------------------------------------------------------------
// Constants
 
const RGBColor  kRGBBlack = { 0x0000, 0x0000, 0x0000 } ;
const RGBColor  kRGBWhite = { 0xFFFF, 0xFFFF, 0xFFFF } ;
const int       kMyAboutDialogID = 128 ;
const int       kMyFatalDialogID = 129 ;
const int       kQD3DAlertID = 27309 ;
//--------------------------------------------------------------------------------------------
// Types
typedef struct _viewerData {
    TQ3ViewerObject     theViewer ;
    FSSpec              theFile ;
    Boolean             isFileValid ;
} ViewerData, *ViewerDataPtr, **ViewerDataHandle ;
 
//--------------------------------------------------------------------------------------------
//
//
 
main()
{
    MoreMasters(); MoreMasters() ; MoreMasters() ;
    MaxApplZone() ;         // Maximise the heap - the viewer requires at least 32k
    InitToolbox() ;
 
    // WE DON'T CHECK FOR 68K machine.
    // Instead I use the NotPPC.rsrc resource file.  This is a file with a 68k CODE 0
    // and CODE 1 resource that puts up a dialog that says "this app only runs on a power
    // macintosh computer.
    
    if( SupportsAEVT() && SupportsQuickDraw3D() && SupportsQuickDraw3DViewer()  ) {
    
        // AppleEvent stuff:
        // Set up the self-addressed descriptor record.
        gSelfPSN.highLongOfPSN = 0;
        gSelfPSN.lowLongOfPSN = kCurrentProcess;        //* Use this instead of GetCurrentProcess *//
        FailIfErr(AECreateDesc(typeProcessSerialNumber,(Ptr)&gSelfPSN,sizeof(ProcessSerialNumber),&gSelfAddress));
 
        RegisterMyEvents() ;    // register the appleevents for this app
 
        MainEventLoop() ;       // Handle events 'til we die
    } 
    else {
        Str255 theString ;
        GetIndString(theString,kQD3DAlertID,3);
        ParamText( theString, 0L,  0L,  0L ) ;
        (void)Alert(kQD3DAlertID,nil);
    }
}
//---------------------------------------------------------------------
 
Boolean SupportsQuickDraw3D(void) 
{
    OSErr err;
    long response;
        
    err = Gestalt(gestaltQD3D,&response);
    if (err!=noErr)
        return false;
        
    return (response && (response << gestaltQD3DAvailable));
}
 
//---------------------------------------------------------------------
 
Boolean SupportsQuickDraw3DViewer(void) 
{
    OSErr err;
    long response;
        
    err = Gestalt( gestaltQD3DViewer,&response );
    if (err!=noErr)
        return false;
        
    return (response && ( response << gestaltQD3DViewerAvailable ));
}
 
//--------------------------------------------------------------------------------------------
//
//
void FailIfErr( OSErr something )
{ 
    OSErr myErr ; 
    if(( myErr = something) != noErr ) { 
        ModalFilterUPP      theProc ;
        DialogPtr           theDialog ; 
        short               itemHit ;
        Str255              theError ;
        
        NumToString(something,theError);
    
        theDialog = GetNewDialog ( kMyFatalDialogID, nil, (WindowPtr)-1 );
        
        // these two lil' snappers are system 7 only
        // so if you use them, check before!!
        // in this app we will only run on Power
        // Macintosh, so we don't check
        
        GetStdFilterProc( &theProc ) ;
        SetDialogDefaultItem(theDialog, ok) ;
        
        ParamText( theError, 0L, 0L, 0L ) ;
        
        // put the dialog up and loop 'til
        // the user hits the OK button
 
        do {
            ModalDialog ( theProc, &itemHit );
        } while( itemHit != ok ) ;
        
        DisposeDialog ( theDialog );
        
        ExitToShell() ; 
    } 
} 
 
//--------------------------------------------------------------------------------------------
//
//
 
void InitToolbox()
{
    Handle      menuBar = nil;
 
 
    InitGraf((Ptr) &qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs((long)nil);
    InitCursor();
 
    // initialize application globals
    
    gQuitFlag = false;
    
    
    menuBar = GetNewMBar(128);              // Read menus into menu bar, MBAR res id is 128
    
    if ( menuBar == nil )
         ExitToShell();                     // if we dont have it then quit - your app 
                                            // needs a dialog here
 
    SetMenuBar(menuBar);                    // Install menus
    DisposeHandle(menuBar);
    
    AppendResMenu(GetMenuHandle(mApple), 'DRVR');   // Add DA names to Apple menu, ID 128
 
    MyAdjustMenus() ;
    DrawMenuBar();
}
 
 
//--------------------------------------------------------------------------------------------
//
//
void MainEventLoop()
{
    EventRecord         event;
    WindowPtr           theWindow;
    Boolean             wasViewerEvent ;
    GrafPtr             savedPort ;
    Point               localPt ;
    TQ3ViewerObject     theViewer ;
    ViewerDataHandle    myData ;
 
    MyAdjustMenus() ;
    while( !gQuitFlag )
    {
        if (WaitNextEvent( everyEvent, &event, 0, nil ))
        {
            
            if((theWindow = FrontWindow()) != nil ) {
            
                myData = (ViewerDataHandle)GetWRefCon(theWindow);
                theViewer = (**myData).theViewer;
            }
            
            if( theViewer ) {
                GetPort( &savedPort ) ;
                SetPort( (GrafPtr)theWindow ) ;
                GetMouse(&localPt);
                if (!Q3ViewerAdjustCursor(theViewer, &localPt))
                    InitCursor();
                wasViewerEvent = Q3ViewerEvent ( theViewer, &event );
                SetPort( savedPort ) ;
            }
            else
                wasViewerEvent = false ;
            
            // was it a viewer event????
            if( !wasViewerEvent )
                HandleEvent( &event );
        }
    }
}
 
//----------------------------------------------------------------------------------
//  HandleActivateWindow is called when an event is received that reports that
//  a window is being either activated or deactivated.
 
static void HandleActivateWindow(WindowPtr theWindow, short activate)
{
    if (theWindow) {
        if (activate) {
        
            // do whatever else you'd like to do for a activate event
            LoadScrap() ;
 
        } else {
        
            // do whatever you'd like to do for a deactivate event
            UnloadScrap() ;
        }
    }
}
 
//--------------------------------------------------------------------------------------------
//
//
Boolean     HandleEvent( EventRecord *theEvent )
{
    short               thePart;
    WindowPtr           theWindow ;
    Rect                screenRect;
    GrafPtr             oldPort ;
    Point               aPoint = {100, 100};
    TQ3ViewerObject     theViewer ;
    ViewerDataHandle    myData ;
    
    switch (theEvent->what) {
        case mouseDown:
        
            thePart = FindWindow( theEvent->where, &theWindow );
            
            switch( thePart ) {
                case inMenuBar: 
                    MyAdjustMenus() ;
                    HandleMenuCommand(MenuSelect(theEvent->where));
                    break;
                
                case inDrag:
                    screenRect = (**GetGrayRgn()).rgnBBox;
                    DragWindow( theWindow, theEvent->where, &screenRect );
                    break ;
            
                case inContent:
                    if (theWindow != FrontWindow())
                        SelectWindow( theWindow );
                    break ;
            
                case inGoAway:
                    if (TrackGoAway( theWindow, theEvent->where )) {
                        MyDisposeViewerWindow( theWindow ) ;
                    }
                    break ;
                    
                default:
                    break ;
            }
            break ;
                    
                
        case updateEvt:
        
            theWindow = (WindowPtr)theEvent->message;
            myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
            theViewer = (**myData).theViewer ;
            
            GetPort(&oldPort ) ;    
            SetPort( theWindow );
            
            BeginUpdate( theWindow );
            Q3ViewerDraw( theViewer ) ;
            EndUpdate( theWindow );
            
            SetPort( oldPort ) ;
            
            break ;
            
        case keyDown:
        case autoKey:
            HandleKeyPress(theEvent);
            break;
            
        case diskEvt:
            if ( HiWrd(theEvent->message) != noErr ) 
                (void) DIBadMount(aPoint, theEvent->message);
            break;
            
        case osEvt:
            break ;
        case activateEvt:
            if ((theWindow = (WindowPtr) theEvent->message) != nil) {
                HandleActivateWindow(theWindow, (theEvent->modifiers & activeFlag));
            }
 
            break;
 
        case kHighLevelEvent:                       // Let the Apple Event Manager handle high level event.
            AEProcessAppleEvent(theEvent);
            break;
 
    }
    return true ;
}
 
 
//--------------------------------------------------------------------------------------------
//
//
void HandleKeyPress(EventRecord *event)
{
    char    key;
 
    key = event->message & charCodeMask;
    
    // just check to see if we want to quit...
    
    if ( event->modifiers & cmdKey ) {      /* Command key down? */
        HandleMenuCommand(MenuKey(key));
    } 
}
 
//--------------------------------------------------------------------------------------------
//
//
 
static void HandleAboutApp( void )
{
    ModalFilterUPP      theProc ;
    DialogPtr           theDialog ; 
    short               itemHit ;
 
    theDialog = GetNewDialog ( kMyAboutDialogID, nil, (WindowPtr)-1 );
    
    // these two lil' snappers are system 7 only
    // so if you use them, check before!!
    // in this app we will only run on Power
    // Macintosh, so we don't check
    
    GetStdFilterProc( &theProc ) ;
    SetDialogDefaultItem(theDialog, ok) ;
    
    // put the dialog up and loop 'til
    // the user hits the OK button
    
    do {
        ModalDialog ( theProc, &itemHit );
    } while( itemHit != ok ) ;
    
    DisposeDialog ( theDialog );
}
 
//--------------------------------------------------------------------------------------------
//
//
static OSErr HandleOpenDoc(FSSpec *theFile)
{
    OSErr               err ;
    short               theRef ;
    ViewerDataHandle    myData ;
    TQ3ViewerObject     theViewer ;
    WindowPtr           theWindow ;
 
    // display the contents
    theWindow = (WindowPtr)MyCreateViewerWindow() ;
    
    // open the file
    err = FSpOpenDF( theFile, fsRdPerm, &theRef ) ;
    if (err == noErr)
    {
        myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
        theViewer = (**myData).theViewer ;
        (**myData).theFile = *theFile ;
        (**myData).isFileValid = true ;
        Q3ViewerUseFile(theViewer, theRef) ;
        err = FSClose(theRef) ;
    }
    
    // set the window title
    SetWTitle( theWindow, theFile->name );
    MyAdjustMenus() ;
    return err ;
}
 
 
//--------------------------------------------------------------------------------------------
//
//
void HandleMenuCommand(long menuResult)
{
    short               menuID;
    short               menuItem;
    Str255              daName;
    
 
    short               numTypes = 2 ;
    SFTypeList          myTypes = { '3DMF', 'TEXT', 0 } ;
    OSErr               err ;
    short               theRef ;
    
    ViewerDataHandle    myData ;
    TQ3ViewerObject     theViewer ;
    WindowPtr           theWindow ;
    GrafPtr             savedPort ;
    
    FSSpec              theFile ;
        
    StandardFileReply   theSFReply ;
 
    menuID = HiWrd(menuResult);
    menuItem = LoWrd(menuResult);
    
    switch ( menuID ) {
        //
        //--------------------------------------------------------------------------    
        //
        case mApple:
            switch ( menuItem ) {
 
                case iAbout:
                    HandleAboutApp() ;  
                    break ;
                                
                default:
                    GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
                    (void) OpenDeskAcc(daName);
                    break;
            }
            break;
        //
        //--------------------------------------------------------------------------    
        //
        case mFile:
            switch ( menuItem ) {
                case iNew:
                    // display the contents
                    (void)MyCreateViewerWindow() ;
                    break ;
                
                case iOpen:
                    // Get the file name to open
                    StandardGetFile( nil, numTypes, myTypes, &theSFReply ) ;
                    
                    // did the user cancel, if not open the file?
                    if(theSFReply.sfGood)
                        MySendOpenDoc(&theSFReply.sfFile) ;
 
                    break ;
                    
                    
                case iRevert:
                
                    // we know this can't be called as long as there
                    // is an app window open (MyAdjustMenus) so get the refcon
                    // from the front window and get the FSSpec from that
                    theWindow = FrontWindow() ;
                    myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
                    theFile = (**myData).theFile ;
                    
                    // open the file and read it back into the viewer
                    err = FSpOpenDF( &theFile, fsRdPerm, &theRef ) ;
                    if (err == noErr)
                    {
                        theViewer = (**myData).theViewer ;
                        Q3ViewerUseFile(theViewer, theRef) ;
                        err = FSClose(theRef) ;
                    }
                    GetPort( &savedPort ) ;
                    SetPort((GrafPtr)theWindow) ;
                    InvalRect( &theWindow->portRect ) ;
                    SetPort( savedPort ) ;
                    break ;     
                            
                case iSave:             
                
                    // we know this can't be called as long as there
                    // is an app window open (MyAdjustMenus) so get the refcon
                    // from the front window and get the FSSpec from that
                    theWindow = FrontWindow() ;
                    myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
                    theFile = (**myData).theFile ;
                    theViewer = (**myData).theViewer ;
 
                    // assumes the original file still exists
                    err = FSpOpenDF(&theFile, fsWrPerm, &theRef);
                    if (err == noErr)
                    {
                        Q3ViewerWriteFile(theViewer, theRef);
                        err = FSClose(theRef);
                    }
                    break ;
                
                case iSaveAs:
                    // we know this can't be called as long as there
                    // is an app window open (MyAdjustMenus) so get the refcon
                    // from the front window and get the FSSpec from that
                    theWindow = FrontWindow() ;
                    myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
                    theViewer = (**myData).theViewer ;
 
                    StandardPutFile("\pSave model as:", "\pUntitled", &theSFReply);
                    if (theSFReply.sfGood)
                    {
                        err = FSpOpenDF(&theSFReply.sfFile, fsWrPerm, &theRef);
                        if (err != noErr)
                        {
                            err = FSpCreate(&theSFReply.sfFile, '????', '3DMF', theSFReply.sfScript);
                            if (err == noErr)
                                err = FSpOpenDF(&theSFReply.sfFile, fsCurPerm, &theRef);
                        }
                        if (err == noErr)
                        {
                            Q3ViewerWriteFile(theViewer, theRef);
                            err = FSClose(theRef);
                        }
                        
                        // set up our record of the file location,
                        // update the structure
                        theWindow = FrontWindow() ;
                        myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
                        theViewer = (**myData).theViewer ;
                        (**myData).theFile = theSFReply.sfFile ;
                        (**myData).isFileValid = true ;
                        
                        // reset the window title
                        SetWTitle( theWindow, theSFReply.sfFile.name );
                    }
                    break;              
                
                case iClose:
                    MyDisposeViewerWindow ( FrontWindow() );
                    break ;
                    
                case iQuit:
                    MySendQuitApp();
                    break;
            }
            break;
            
            
        //
        //--------------------------------------------------------------------------    
        //
        case mEdit:
            // display the contents
            theWindow = FrontWindow() ;
            myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
            theViewer = (**myData).theViewer ;
            switch(menuItem)
            {
                case iCut:
                    Q3ViewerCut(theViewer);
                    break;
                case iCopy:
                    Q3ViewerCopy(theViewer);
                    break;
                case iPaste:
                    Q3ViewerPaste(theViewer);
                    break;
                case iClear:
                    Q3ViewerClear(theViewer);
                    break;
                default:
                    break;
            }
            break; 
 
    }
    HiliteMenu(0);      // Unhighlight whatever MenuSelect or MenuKey hilited
}
 
//--------------------------------------------------------------------------------------------
//
//
void MyAdjustMenus( void ) 
{
    WindowPtr           theWindow ;
    ViewerDataHandle    myData ;
    MenuHandle          theMenu ;
 
    theWindow = FrontWindow() ;
    
    
    if( theWindow != nil ) {
    
        theMenu =  GetMenuHandle ( mFile ) ;
        
        EnableItem ( theMenu, iClose );
        EnableItem ( theMenu, iSaveAs );
                
        myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
        
        if( (**myData).isFileValid) {
            EnableItem ( theMenu, iSave );
            EnableItem (theMenu, iRevert );
        }
        else {
            DisableItem ( theMenu, iSave );
            DisableItem ( theMenu, iRevert );
        
        }
        
        EnableItem ( GetMenuHandle ( mEdit ), 0 );
 
    }
    else {
 
        theMenu =  GetMenuHandle ( mFile ) ;
 
        DisableItem ( theMenu, iClose );
        DisableItem ( theMenu, iRevert );
        DisableItem ( theMenu, iSave );
        DisableItem ( theMenu, iSaveAs );
        
        DisableItem ( GetMenuHandle ( mEdit ), 0 );
    }
    
    // we don't support undo
    DisableItem ( GetMenuHandle ( mEdit ), iUndo );
    
    DrawMenuBar() ;
}
 
 
//--------------------------------------------------------------------------------------------
//
//
OSErr   MyDisposeViewerWindow( WindowPtr theWindow )
{
    TQ3ViewerObject     theViewer ;
    ViewerDataHandle    myData ;
    
    if( theWindow == nil)
        return paramErr ;
 
    myData = (ViewerDataHandle)GetWRefCon( theWindow ) ;
    theViewer = (**myData).theViewer ;
    
    DisposeHandle((Handle)myData);
    DisposeWindow(theWindow);
    
    MyAdjustMenus() ;
    return  Q3ViewerDispose(theViewer);
}
 
 
//--------------------------------------------------------------------------------------------
//
//
CGrafPtr MyCreateViewerWindow(  )
{
 
    Rect                theRect ;
    GrafPtr             savedPort ;
    TQ3ViewerObject     myViewerObj ;
    WindowPtr           theWindow ;
    ViewerDataHandle    myData = (ViewerDataHandle)NewHandle(sizeof(ViewerData)) ;
    
    GetPort( &savedPort ) ;
        
    // set the new rect up with a stagger for multiple windows
    SetRect(    &theRect, 
                gStaggerPos.h, 
                gStaggerPos.v, 
                gStaggerPos.h + kWindowWidth, 
                gStaggerPos.v + kWindowHeight );
 
    gStaggerPos.h += 16 ;
    gStaggerPos.v += 16 ;       // this is not "real staggering code, it don't wrap ;       
                         
    theWindow  = NewCWindow(    nil, 
                                &theRect, 
                                "\pUntitled", 
                                false, 
                                documentProc, 
                                (WindowPtr)-1, 
                                true, 
                                0L );   
                    
    SetPort( (GrafPtr)theWindow ) ;
    
    // set up the viewer object here
    
    
    myViewerObj = Q3ViewerNew ((CGrafPtr)theWindow,  &theWindow->portRect,  kQ3ViewerDefault) ; 
    
    //stuff the reference to the viewer in the RefCon field of the Window
    (**myData).theViewer = myViewerObj ;
    (**myData).isFileValid = false ;
    SetWRefCon( theWindow, (long)myData );
    
    // make sure it is visible
    ShowWindow( theWindow ) ;
    
    SetPort( savedPort ) ;
    
    return (CGrafPtr)theWindow ;
}
 
 
//-----------------------------------------------------------------------
// returns true if the platform supports appleevents - we won't run
// if it doesn't
 
Boolean SupportsAEVT(void)
{
    OSErr err;
    long response;
        
    err = Gestalt(gestaltAppleEventsAttr,&response);
    if (err!=noErr)
        return false;
        
    return (response && (response << gestaltAppleEventsPresent));
}
 
//-----------------------------------------------------------------------
// called to register our appleevent handlers
 
void RegisterMyEvents(void)
{
    OSErr err;
    
    if (!SupportsAEVT())
        return;
    
    err = AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,NewAEEventHandlerProc(MyAEHandleOAPP),0L,false);
    if (err!=noErr)
        return;
                
    err = AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,NewAEEventHandlerProc(MyAEHandleODOC),0L,false);
    if (err!=noErr)
        return;
                
    err = AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,NewAEEventHandlerProc(MyAEHandlePDOC),0L,false);
    if (err!=noErr)
        return;
                
    err = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,NewAEEventHandlerProc(MyAEHandleQUIT),0L,false);
    if (err!=noErr)
        return;
}
 
//-----------------------------------------------------------------------
// open application event handler for the core event suite, 
// by default we just want a blank new document
 
pascal OSErr MyAEHandleOAPP( AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
{
    // we don't actually do anything on open - you could,
    // for example you might want to open a blank untitled 
    // window
    
    OSErr err = noErr ;
    return err;
}
 
 
//-----------------------------------------------------------------------
// handler for the open document appleevent handler
 
pascal OSErr MyAEHandleODOC(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
{
    FSSpec      myFSS;
    AEDescList  docList;
    OSErr       err,
                ignoreErr;
    long        index,
                itemsInList;
    Size        actualSize;
    AEKeyword   keywd;
    DescType    returnedType;
 
    
    err = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&docList);
    if (err == noErr) {
    
        // see how many descriptor items are in the list
        // this is the number of documents we want to open
        err = AECountItems(&docList,&itemsInList);
 
        // now get each descriptor record from the list
        // coerce the returned data to an FSSpec record, and
        // open the asoociated file
        
        for (index=1; index <= itemsInList && err == noErr; index++) {
        
            err = AEGetNthPtr(  &docList, 
                                index,
                                typeFSS,
                                &keywd,
                                &returnedType,
                                (Ptr)&myFSS,
                                sizeof(myFSS),
                                &actualSize);
    
            if (err == noErr)   {
            
                FInfo       fndrInfo ;
                
                // we now have a valid FSSpec to reference the file, we need to know 
                // what type the file is to determine which file open function to call
                // we can determine this from the finder info for the file
                
                err = FSpGetFInfo( &myFSS, &fndrInfo ); 
                
                // if we got that ok, then we switch on the file  
                // type (we don't care about the creator type)  
                        
                if (err == noErr)   {
                
                    switch( fndrInfo.fdType ) {
                        case 'TEXT':
                        case '3DMF':
                            err =  HandleOpenDoc(&myFSS);
                            break ;
                    }
                }
            }
        }
        ignoreErr = AEDisposeDesc(&docList);
    }
    return err ;
}
 
//-----------------------------------------------------------------------
// handler for the print document event handler
 
pascal OSErr MyAEHandlePDOC(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon)
{
    FSSpec      myFSS;
    AEDescList  docList;
    OSErr       err;
    long        index,
                itemsInList;
    Size        actualSize;
    AEKeyword   keywd;
    DescType    returnedType;
 
    
    err = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&docList);
    if (err == noErr) {
    
        // see how many descriptor items are in the list
        // this is the number of documents we want to open
        err = AECountItems(&docList,&itemsInList);
 
        // now get each descriptor record from the list
        // coerce the returned data to an FSSpec record, and
        // open the asoociated file
        
        for (index=1; index <= itemsInList && err == noErr; index++) {
        
            err = AEGetNthPtr(  &docList, 
                                index,
                                typeFSS,
                                &keywd,
                                &returnedType,
                                (Ptr)&myFSS,
                                sizeof(myFSS),
                                &actualSize);
    
            if (err == noErr)   {                   
                // err = HandlePrintDoc( &myFSS );
                err = errAEEventNotHandled ;        // we don't do this yet...
            }
        }
        err = AEDisposeDesc(&docList);
    }
    return err ;
}
 
//-----------------------------------------------------------------------
// quit appleevent handler
 
pascal OSErr MyAEHandleQUIT(AppleEvent *theAppleEvent,AppleEvent *reply,long refCon)
{
    OSErr           err = noErr ;       // used as return value
    WindowPtr       theWindow ;
    Boolean         quitting = true ;
 
    
    // close all windows and signal to Quit
 
        
    // attempt to close all documents
    while(( theWindow = FrontWindow()) != nil && quitting )
        quitting = (MyDisposeViewerWindow( theWindow ) == noErr);   
        
 
    // if we closed everything up successfully, we can return noErr, otherwise
    // indicate to sender of the 'quit' aevt that we canceled
    
    if (quitting) {
        gQuitFlag = true;                   // user didn't cancel
        AEDisposeDesc(&gSelfAddress);       // Dispose of my self-addressed descriptor.
    }
    else {
        err = userCanceledErr ;
    }
            
    return err ;
}
 
 
//----------------------------------------------------------------------------------//
//  Send a Quit Application Apple Event to myself to terminate this app.        
 
void MySendQuitApp( void )
{
    AppleEvent  myAppleEvent, reply;
    
    //  Create the Apple Event.
    FailIfErr(AECreateAppleEvent( kCoreEventClass, 
                                  kAEQuitApplication, 
                                  &gSelfAddress,
                                  kAutoGenerateReturnID, 
                                  kAnyTransactionID, 
                                  &myAppleEvent));
                                  
    //  Send the Apple Event.
    FailIfErr(AESend( &myAppleEvent, 
                      &reply, 
                      kAENoReply+kAENeverInteract, 
                      kAENormalPriority,
                      kAEDefaultTimeout, 
                      nil, 
                      nil));
                      
    AEDisposeDesc(&myAppleEvent);               // Dispose of the Apple Event.
} // MySendQuitApp
 
 
//----------------------------------------------------------------------------------//
//  Send a Open Document Application Apple Event to myself to open a document.      
 
void MySendOpenDoc(FSSpec *myFSSpec)
{
    AppleEvent    myAppleEvent;
    AppleEvent    defReply;
    AEDescList    docList;
    OSErr         myErr;
    OSErr         ignoreErr;
    
    myAppleEvent.dataHandle = nil;
    docList.dataHandle  = nil;
    defReply.dataHandle = nil;
        
    // Create empty list and add one file spec
    FailIfErr(AECreateList(nil,0,false, &docList));
    
    FailIfErr(AEPutPtr(&docList,1,typeFSS,(Ptr)myFSSpec,sizeof(FSSpec)));
        
    FailIfErr(AECreateAppleEvent(   kCoreEventClass,
                                    kAEOpenDocuments,
                                    &gSelfAddress,
                                    kAutoGenerateReturnID,
                                    kAnyTransactionID,
                                    &myAppleEvent));
 
    // Put Params into our event and send it
 
    FailIfErr(AEPutParamDesc( &myAppleEvent,
                              keyDirectObject,
                              &docList));
 
    FailIfErr(AESend( &myAppleEvent,
                      &defReply,
                      kAENoReply+kAENeverInteract,
                      kAENormalPriority,
                      kAEDefaultTimeout,
                      nil,
                      nil));
        
        
    if (myAppleEvent.dataHandle) 
        ignoreErr = AEDisposeDesc(&myAppleEvent);
        
    if (docList.dataHandle) 
        ignoreErr = AEDisposeDesc(&docList);
            
}   // MySendOpenDoc