CoreSample.c

/*
    File:       CoreSample.c
 
    Contains:   An application that is Apple Event-aware, Scripting Compatible,     
                and recordable. It supports the Required and Core Suite of          
                Apple Events, the Object Model, and the Open Scripting              
                Architecture.
                                                                                                    
                The main purpose of this sample code is to demonstrate how to develop an            
                application that is Apple event-aware, scripting compatible, uses the Object        
                Support Library, and supports Apple's Open Scripting Architecture.  In              
                addition, it has its own 'aete' (Apple Event Terminology Extension) resource        
                (CoreSampleAETE.r). By  incorporating these technologies into your application, 
                your application will support Apple's Open Scripting Architecture.                  
                                                                                        
                The functionality of CoreSample is basic window manipulation. The user may          
                create, drag, size, zoom, and close windows.  All these actions may be              
                performed through Apple events.                                                     
                                                                                            
                This application is also "factored", which means that user interactions (such       
                as dragging or sizing a window, selecting a menuitem) are converted into Apple      
                events which the application sends off to itself, and then is handled by the        
                corresponding event handler.  Factoring makes it possible to access the appli-      
                cation's functionality through Apple events. It also makes it easier to record      
                the user's actions in the form of Apple events.                                     
                                                                                            
                CoreSample supports the Required and Core suites of events, and the application     
                and window object classes. One additional property has been added to the window     
                class, and that is its position, the top left-hand coordinates of the window.       
                Some events only apply to the window class, such as Create, Move, Clone, and        
                Set Data (application properties are not modifiable, except for pClipboard,         
                which I do not support).  Currently, CoreSample supports the Simple Grammar,        
                as defined in the "Object Support Library Developer Note".                          
                                                                                            
                The properties you may access with the Get Data Apple event are as follows:         
                    Application - Best Type, Default Type, Class, Name, IsFrontProcess, Version     
                    Window - Best Type, Default Type, Bounds, Class, Index, Name, Position,         
                     Closeable, Titled, Resizable, Zoomable, Floating, Modal, Zoomed,       
                     and Visible.                                                           
                The properties you may set with the Set Data Apple event are as follows:            
                    Window - Bounds, Index, Zoomed, Name, Position, and Visible.                    
                                                                                            
                When you create a new element, you may pass it initial data values. This            
                application will create the new element accordingly if either or both of the        
                initial data parameters exist. In addition, with CoreSample, you may create or      
                move a window without passing it an insertion location record. By default, a        
                window will be created/moved to the frontmost position.                             
                                                                                            
                (NOTE: Some portions of this code are derived from TESample, a                      
                sample application provided by Apple Developer Technical Support.)                  
 
    Written by: Sue Dumont  
 
    Copyright:  Copyright © 1992-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                7/21/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                12/1/93     <dan>           added PowerPC support - will run native on PowerPC if   
                                            compiled on PowerPC system. These changes are denoted       
                                            by [pwpc].
                6/22/93     <doo>           converted files to run in the Think C 6.0 environment   
                                            Fixed incorrect comparison of rects and windowlist problems 
                                            associated with the Think compiler. 
                4/02.93     <smd>           added GetWindowBounds routine to calculate the correct  
                                            bounds when the bounds accessed from the content region is  
                                            invalid (such as when the application is hidden).               
                                        -   cleaned up the aete.
                10/01/92    <smd>           Added pVersion to application and now set the port before   
                                            setting the pPosition property.     
                07/19/92    <smd>           Fixed bug where the Move event was not recording the    
                                            correct window being moved when the data was being passed   
                                            by index rather than by name.   
                04/30/92    <smd>           Check if replacing the same window in HandleMove    
                                            (i.e., "move window 2 to window 2"). If so, do nothing.     
                06/25/92    <smd>           Changed FindRelativeWindow to return the windowPtr of the       
                                            window being replaced rather than closing it. This caused       
                                            an error when trying to replace the same window, in which       
                                            case nothing should happen. (Ex. move window 2 to window 2).
                04/27/92    <smd>           Fixed bug in DoSetData where data was set to a pointer, and 
                                            then the pointer was diposed of.
                04/20/92    <smd>           Fixed a bug with setting the visibility property of a window.
                02/28/92    <smd>           Added coercion routines (thanks Kevin) to clean up code.    
                                            These convert from descs to boolean, long, and pstrings.
                02/25/92    <smd>           Modified GetWindowWithTitle, GetWidnowWithIndex, and    
                                            GetWindowIndexNum routines to use WindowList so ALL windows     
                                            will be accessed (even invisible ones).                         
                                         -  Changed InitializeDescs to MyInitDescs and DisposeDescs to  
                                            MyDisposeDescs.                                                 
                                         -  Removed the FailIfErr calls from the AE Handlers so that        
                                            they will return the error code rather than dying.
                02/24/92    <smd>           Now sends a Move event when just making a window active.    
                                            This is done in the DoEvent routine, drag region.
                02/21/92    <smd>           Fixed bug where the same AEDesc was being passed as source  
                                            and dest to AECoerceDesc().                                     
                                            Send myself a Move event when user clicks in content of a       
                                            window.
                02/17/92    <smd>           Added InitializeDescs() and DisposeDescs() routines.    
                02/05/92    <smd>           Handling optional parameters in Create Element event.
                01/30/92    <smd>           Adding complete support for core suite and properties.
                01/21/92    <smd>           Positive and negative offset when referencing by index.
                01/10/92    <smd>           Made insertion location parameter optional in the Create
                                            and Move events, and provided my own default behavior.  
                01/09/92    <kc>            Quick clean up for Scripting QuickStart.        
                01/06/92    <kc>            Added code for Count Elements, Do Objects Exist, Move,
                                            and Get Data Size
                11/91       <smd>           Initial code implementation.                    
 
*/
#include    <Types.h>
#include    <Quickdraw.h>
#include    <Events.h>
#include    <AppleEvents.h>
#include    <AEObjects.h>
#include     <AEPackObject.h>
#include    <Resources.h>                   // for version resource
#include    <Windows.h>
#include    <Menus.h>
#include    <Dialogs.h>
#include    <Desk.h>
#include    <Scrap.h>
#include    <limits.h>
#include    <ToolUtils.h>
#include    <Memory.h>
#include    <SegLoad.h>
#include    <OSUtils.h>
#include    <OSEvents.h>
#include    <DiskInit.h>
#include    <Packages.h>
#include    <Traps.h>
#include    <string.h>
#include    <Strings.h>
#include    <stdarg.h>
#include    "AERegistry.h"              // Constants defined in the Registry.
#include    "CoreSample.h"
#include    <LowMem.h>
 
#define HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
#define LoWrd(aLong)    ((aLong) & 0xFFFF)
 
typedef  long*          LongPtr;
typedef  WindowPeek*    PeekPtr;
 
    //  Globals.
SysEnvRec       gMac;                   // Contains the system environment
Boolean         gHasWaitNextEvent;      // True if WaitNextEvent trap is available
Boolean         gInBackground;          // Determines if currently in the background
long            gNumWindowsOpen;        // The number of windows open
short           gNewWindows;            // The number of new windows created
Boolean         gQuitApp;               // True to quit the application
AEDesc          gNullDesc;              // A null descriptor record
AEAddressDesc   gSelfAddress;           // A self-addressed address descriptor record
ProcessSerialNumber gSelfPSN;           // This application's psn
short           gRefNum;                // reference number of rescource file
 
 
//----------------------------------------------------------------------------------//
//          PROTOTYPES                                                              //
//----------------------------------------------------------------------------------//
void        AdjustMenuStates(void);
void        AlertUser(short error);
void        CloseTheWindow(WindowPtr window);
WindowPtr   DoCreateNewWindow(WindowPtr behind);
OSErr       CreateWindowObjectSpec(WindowPtr window,short formType,AEDesc *objectSpec);
void        DoEvent(EventRecord *event);
void        DoGrowWindow(WindowPtr window, EventRecord *event);
void        DoMenuCommand(long menuResult);
OSErr       DoSetData(AEDesc *token, AEDesc *data);
void        DoUpdate(WindowPtr window);
void        EventLoop(void);
void        FailIfErr(OSErr error);
OSErr       FindRelativeWindow(WindowPtr *window,AEDesc *object,DescType pos,WindowPtr *replaceWindow);
OSErr       GetAppData(DescType theProperty, AEDesc *result);
OSErr       GetMissingParams(AppleEvent *theAppleEvent);
OSErr       GetWindowData(DescType property, WindowPtr window, AEDesc *result);
long        GetWindowIndexNum(WindowPtr window);
WindowPtr   GetWindowAtIndex(long index);
WindowPtr   GetWindowWithTitle(ConstStr255Param title);
void        InitAEHandlers(void);
void        Initialize(void);
Boolean     IsAppWindow(WindowPtr window);
Boolean     IsDAWindow(WindowPtr window);
Boolean     IsTrapAvailable(short tNumber, TrapType tType);
void        ReportError(AppleEvent *reply, long err);
WindowPtr   ResolveToWindow(AEDesc *objectSpecifier);
void        SendClose(WindowPtr  window);
void        SendCreateElement(void);
void        SendMoveEvent(WindowPtr windowToMove, long index);
void        SendQuitApp(void);
void        SendSetData(AEDesc *pDesc, AEDesc *pData, AEDesc *object);
void        SetUpPropertyData(WindowPtr window,DescType propType,DescType dataType,Size dataSize);
void        SignalError(short error);
void        Terminate(void);
void        ZoomIt(WindowPtr window, short part);
Rect        DoGetWindowBounds(WindowPtr window);
void        MakeNewWindowTitle( short       num,                // Window number.
                         Str255     title);
void        MyInitDescs(AEDesc*  desc1, ... );
void        MyDisposeDescs(AEDesc*  desc1, ... );
OSErr       DescToBoolean(const AEDesc* desc, Boolean* boolvalue);
OSErr       DescToLong(const  AEDesc* desc, long* longvalue);
OSErr       DescToPString(const AEDesc* desc, Str255 str, short maxLength);
pascal OSErr HandleOpenApp(AppleEvent *theAppleEvent, AppleEvent* reply, long refCon);
pascal OSErr HandleQuitApp(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
WindowPtr   DoCloneWindow(WindowPtr windowToClone, WindowPtr behindWindow);
pascal  OSErr HandleClone(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
pascal  OSErr HandleClose(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
pascal  OSErr HandleCountElements(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
pascal  OSErr HandleCreateElement(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
pascal  OSErr HandleDoObjectsExist(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
pascal  OSErr HandleSetData(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
pascal  OSErr HandleGetData( AppleEvent*    theAppleEvent,
                     AppleEvent*    reply,
                     long           refCon  );
pascal  OSErr HandleMove(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
pascal  OSErr DummyHandler( AppleEvent      *theAppleEvent,
                    AppleEvent      *reply,
                    long            refCon  );
pascal  OSErr WindowAccessor( DescType      classWanted,        // window class
                      AEDesc*       container,          // the application (null container)
                      DescType      containerClass, 
                      DescType      keyform,
                      AEDesc*       selectionData,
                      AEDesc*       resultToken,        // specified window is returned in result
                      long          theRefCon   );
pascal  OSErr WindowPropertyAccessor( DescType      classWanted,        // Property class
                              AEDesc*       container,          // Window object
                              DescType      containerClass, 
                              DescType      form,
                              AEDesc*       selectionData,
                              AEDesc*       resultToken,
                              long          theRefCon   );
pascal  OSErr AppPropertyAccessor(  DescType        classWanted,            // Property class.
                            AEDesc*         container,              // Application.
                            DescType        containerClass, 
                            DescType        form,
                            AEDesc*         selectionData,
                            AEDesc*         resultToken,
                            long            theRefCon   );
extern pascal OSErr CreateObjSpecifier(DescType theClass, AEDesc *theContainer,
                        DescType keyForm, AEDesc *keyData, Boolean disposeInputs, 
                        AEDesc *objSpecifier);
extern void _DataInit();
 
 
//----------------------------------------------------------------------------------//
#pragma segment Main
void main()
{
#ifndef THINK_C
    UnloadSeg((Ptr) _DataInit);     // Note that _DataInit must not be in Main!
#endif
 
    MaxApplZone();                  // Expand the heap so code segments load at the top.
    Initialize();                   // Initialize the program
    
#ifndef THINK_C                     // Initialize the program
    UnloadSeg((Ptr)Initialize);     // Note that Initialize must not be in Main!
#endif
 
    EventLoop();                    // Call the main event loop
}
 
//----------------------------------------------------------------------------------//
// Continue retrieving events until the application terminates.                     //
//----------------------------------------------------------------------------------//
#pragma segment Main
void EventLoop()
{
    RgnHandle       cursorRgn;
    Boolean         gotEvent;
    EventRecord     event;
 
    cursorRgn = NewRgn();
    gQuitApp = false;               // This is set to true in Terminate().      
    
    while (!gQuitApp)               // Loop until user quits or error.
    {
        if (gHasWaitNextEvent)
            gotEvent = WaitNextEvent(everyEvent, &event, LONG_MAX, cursorRgn);
        else 
        {
            SystemTask();
            gotEvent = GetNextEvent(everyEvent, &event);
        }
        if (gotEvent)
            DoEvent(&event);
    }
}
 
//----------------------------------------------------------------------------------//
//  Find out which event this is and send it off to its appropriate handler.        //
//  When the user clicks in the drag region, either one of two events may be        //
//  triggered. The set position property (set data event) would occur if the widnow //
//  is dragged to another location, or the move event would be sent if the window   //
//  is just made active. In the latter case, the window's index before being        //
//  moved to the front is passed to SendMoveEvent for recording purposes.           //
//----------------------------------------------------------------------------------//
#pragma segment Main
void DoEvent( EventRecord*  event )
{
    long        index=0;
    short       part, err;
    WindowPtr   window;
    char        key;
    Rect        bounds1, bounds2;
    Point       aPoint;
 
    switch (event->what)
    {
        case mouseDown:
            part = FindWindow(event->where, &window);
            switch (part) 
            {
                case inMenuBar:
                    AdjustMenuStates();         
                    DoMenuCommand(MenuSelect(event->where));
                    break;
                    
                case inSysWindow:
                    SystemClick(event, window);
                    break;
                    
                case inContent:
                    if (window != FrontWindow()) 
                        SendMoveEvent(window, index);
                    break;
                    
                case inDrag:
                    index = GetWindowIndexNum(window);
                    bounds1 = (*((WindowPeek)window)->contRgn)->rgnBBox;
                    DragWindow(window, event->where, &qd.screenBits.bounds);
                    bounds2 = (*((WindowPeek)window)->contRgn)->rgnBBox;
                    if ((bounds1.left == bounds2.left) && 
                            (bounds1.top == bounds2.top))
                        SendMoveEvent(GetWindowAtIndex(index), index);
                    else
                        SetUpPropertyData(window,pPosition,typeQDPoint,sizeof(Point));
                    break;
                    
                case inGoAway:
                    if (TrackGoAway(window, event->where))
                        SendClose(window);
                    break;
                    
                case inGrow:
                    DoGrowWindow(window, event);
                    break;
                    
                case inZoomIn:                          // For recording purposes, we send an Apple
                case inZoomOut:                         // event to ourselves to set the bounds property.
                    if (TrackBox(window, event->where, part))
                    {
                        ZoomIt(window, part);
                        SetUpPropertyData(window, pIsZoomed, typeBoolean, sizeof(Boolean));
                    }
                    break;
            }
            break;
            
        case keyDown:
        case autoKey:                               // Only handle menu key equivalents
            key = event->message & charCodeMask;
            if (event->modifiers & cmdKey)      // Command key down
            {
                if (event->what == keyDown) 
                {
                    AdjustMenuStates();             // Enable/disable/check menu items properly
                    DoMenuCommand(MenuKey(key));
                }
            } 
            break;
            
        case activateEvt:
            DrawGrowIcon((WindowPtr)event->message);
            break;
            
        case updateEvt:
            DoUpdate((WindowPtr) event->message);
            break;
            
        case diskEvt:
            if (HiWord(event->message) != noErr)
            {
                SetPt(&aPoint, kDILeft, kDITop);
                err = DIBadMount(aPoint, event->message);
            }
            break;
            
        case kOSEvent:
            {
                switch ((event->message >> 24) & 0x0FF)         // High byte of message.
                {
                    case kMouseMovedMessage:
                        break;                      // Do nothing if mouse moved.
                    
                    case kSuspendResumeMessage:     // suspend/resume is also an activate/deactivate
                        SetCursor(&qd.arrow);
                        if (IsAppWindow(window = FrontWindow()))
                            DrawGrowIcon(window);
                        break;
                }
            }
            break;
            
        case kHighLevelEvent:                       // Let the Apple Event Manager handle high level event.
            AEProcessAppleEvent(event);
            break;
 
        default:
            break;
    }
}
 
//----------------------------------------------------------------------------------//
//  Handle the mouseDown event in the grow box region of the window.  If the        //
//  window has been resized, an Apple Event is sent to set the bounds property.     //
//  This is done for recording purposes.                                            //
//----------------------------------------------------------------------------------//
#pragma segment Main
void DoGrowWindow(  WindowPtr    window,
                    EventRecord* event  )
{
    long            result;
    Rect            tempRect;
 
    tempRect = qd.screenBits.bounds;        // Set up the limiting values.
    tempRect.top = kMinWinDim;
    tempRect.left = kMinWinDim;
    result = GrowWindow(window, event->where, &tempRect);
    if (result)                         // Did window actually change size?
    {
        SetPort(window);
        InvalRect(&window->portRect);
        SizeWindow(window, LoWrd(result), HiWrd(result), true);
        InvalRect(&window->portRect);       // Send event for recording purposes.
        SetUpPropertyData(window, pBounds, typeQDRectangle, sizeof(Rect));
    }
}
 
//----------------------------------------------------------------------------------//
//  Zoom the window and set the refcon field to reflect its zoomed state.           //
//----------------------------------------------------------------------------------//
#pragma segment Main
void ZoomIt( WindowPtr  window,
             short      part  )
{
    SetPort(window);
    EraseRect(&window->portRect);           // We just have a blank window.
    ZoomWindow(window, part, window == FrontWindow());
    SetWRefCon(window, (long)part == inZoomOut);    // Set to true if zoomed.
    InvalRect(&window->portRect);
}
 
//----------------------------------------------------------------------------------//
//  This is called when an update event is received for a window.                   //
//----------------------------------------------------------------------------------//
#pragma segment Main
void DoUpdate( WindowPtr  window )
{
    if (IsAppWindow(window)) 
    {
        BeginUpdate(window);
        SetPort(window);
        EraseRect(&window->portRect);           // We just have an empty window.
        DrawGrowIcon(window);
        EndUpdate(window);
    }
}
 
//----------------------------------------------------------------------------------//
//  Set up the menus according to the current state.                                //
//----------------------------------------------------------------------------------//
#pragma segment Main
void AdjustMenuStates()
{
    WindowPtr       window;
    MenuHandle      menu;
 
    window = FrontWindow();
    menu = GetMenuHandle(mFile);
    if (gNumWindowsOpen < kMaxOpenWindows)
        EnableItem(menu, iNew);         // Enable New if we can open more windows.
    else
        DisableItem(menu, iNew);
    if (window)
        EnableItem(menu, iClose);       // Enable Close if there is a window to close.
    else
        DisableItem(menu, iClose);
}
 
//----------------------------------------------------------------------------------//
//  This is called when an item is chosen from the menu bar.                        //
//----------------------------------------------------------------------------------//
#pragma segment Main
void DoMenuCommand(long  menuResult)
{
    short       menuID, menuItem;
    short       itemHit, daRefNum;
    Str255      daName;
    WindowPtr   window;
 
    window = FrontWindow();
    menuID = HiWord(menuResult);
    menuItem = LoWord(menuResult);
    switch (menuID)
    {
        case mApple:
            switch (menuItem) 
            {
                case iAbout:
                    itemHit = Alert(rAboutAlert, nil);
                    break;
                default:            // all other items in this menu are DA's.
                    GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
                    daRefNum = OpenDeskAcc(daName);
                    break;
            }
            break;
            
        case mFile:
            switch (menuItem)               // All these items send Apple events to
            {                               // handle the selection.
                case iNew:
                    SendCreateElement();
                    break;
                case iClose:
                    SendClose(FrontWindow());
                    break;
                case iQuit:
                    SendQuitApp();
                    break;
            }
            break;
        
        case mEdit:                 // Call SystemEdit for DA editing & MultiFinder.
            SystemEdit(menuItem-1);
            break;
    }
    HiliteMenu(0);                  // Unhighlight what MenuSelect (or MenuKey) hilited.
}
 
//----------------------------------------------------------------------------------//
//  This routine appends the ascii representation of num to the title string.       //
//----------------------------------------------------------------------------------//
#pragma segment Main
void MakeNewWindowTitle( short      num,                // Window number.
                         Str255     title)              // Window title.
{
    short       i, count, index;
    char        numStr[5];
    
    i = 0;
    do {
            numStr[i++] = num % 10 + '0';
        } while (num /= 10);
        
    index = title[0] + 1;                   // Get length of title string.
    
    for (count = i-1; count >= 0; count--)
        title[index++] = numStr[count];
    title[0] += i;
}       
 
//----------------------------------------------------------------------------------//
//  Create a new window behind the given window.  Use the window's refCon           //
//  field to indicate whether the window is zoomed or not.                          //
//----------------------------------------------------------------------------------//
#pragma segment Main
WindowPtr DoCreateNewWindow(WindowPtr behindWindow)
{
    Ptr         storage;
    WindowPtr   newWindow, firstWindow;
    Rect        bounds;
    Str255      title;
 
    if (gNumWindowsOpen < kMaxOpenWindows)
    {
        storage = NewPtr(sizeof(WindowRecord));
        if (storage != nil) 
        {
            newWindow = GetNewWindow(rDocWindow, storage, behindWindow);
            if (newWindow != nil)
            {
                gNumWindowsOpen++;          // Increment the number of windows currently open.
                gNewWindows++;              // Increment the number of new windows created.
                GetWTitle(newWindow, title);
                MakeNewWindowTitle(gNewWindows, title);
                SetWTitle(newWindow, title);
                if (firstWindow = FrontWindow())
                {
        //¥¥¥           bounds = (*((WindowPeek)firstWindow)->contRgn)->rgnBBox;
                    bounds = DoGetWindowBounds(firstWindow);
                    MoveWindow(newWindow, bounds.left+30, bounds.top+30, false);
                }
                SetWRefCon(newWindow, 0L);          // set zoom state to false.
                SetPort(newWindow);
                return(newWindow);
            }
        else
            DisposePtr(storage);        // Dispose of the storage if it is not used.
        }
    }
    return(nil);
}
 
//----------------------------------------------------------------------------------//
//  Close the given window or desk accessory.                                       //
//----------------------------------------------------------------------------------//
#pragma segment Main
void CloseTheWindow(WindowPtr  window)
{
    if (IsDAWindow(window))
        CloseDeskAcc(((WindowPeek)window)->windowKind);
    else 
        if (IsAppWindow(window))
        {
            CloseWindow(window);
            DisposePtr((Ptr)window);
            gNumWindowsOpen--;
        }
}
 
//----------------------------------------------------------------------------------//
//  Returns true if the window belongs to this application, else false.             //
//----------------------------------------------------------------------------------//
#pragma segment Main
Boolean IsAppWindow(WindowPtr  window)
{
    if (!window)
        return(false);
    else 
        return(((WindowPeek)window)->windowKind == userKind);
}
 
//----------------------------------------------------------------------------------//
//  Returns true if the given window belongs to a DA, else false is returned.       //
//----------------------------------------------------------------------------------//
#pragma segment Main
Boolean IsDAWindow(WindowPtr  window)
{
    if (window == nil)
        return(false);
    else                    // DA windows have negative windowKinds.
        return(((WindowPeek)window)->windowKind < 0);
}
 
//----------------------------------------------------------------------------------//
//  If an error has occurred, I check the user interaction level. If I can          //
//  interact with the user, I put up a dialog and exit the application; otherwise,  //
//  I just exit the application.                                                    //
//                                                                                  //
//  ***NOTE: Real applications would not handle errors in this fashion!  If they    //
//  cannot interact with the user, they should abort the Apple event handler and    //
// return the error in the reply parameter.                                         //
//----------------------------------------------------------------------------------//
#pragma segment Main
void FailIfErr(OSErr  error)
{
    if (error)
    {
        if (!(AEInteractWithUser(kNoTimeOut, nil, nil)))            // Can we interact?
            AlertUser(eAEError);                                    // Yes, so put up the dialog.
        ExitToShell();
    }
}
 
//----------------------------------------------------------------------------------//
//  Display an alert for the user to indicate that an error has occurred.           //
//----------------------------------------------------------------------------------//
#pragma segment Main
void AlertUser(short  error)
{
    short       itemHit;
    Str255      message;
 
    GetIndString(message, kErrStrings, error);
    ParamText(message, (ConstStr255Param)"\p", (ConstStr255Param)"\p", (ConstStr255Param)"\p"); // [pwpc]
    itemHit = Alert(rUserAlert, nil);
}
 
//----------------------------------------------------------------------------------//
//  Quit the application by closing all windows and setting the quit flag to true.  //
//----------------------------------------------------------------------------------// 
#pragma segment Main
void Terminate()
{
    WindowPtr   aWindow;
 
    while(aWindow = FrontWindow())
        CloseTheWindow(aWindow);
    AEDisposeDesc(&gSelfAddress);           // Dispose of my self-addressed descriptor.
    gQuitApp = true;
}
 
//----------------------------------------------------------------------------------//
//  Perform the initialization necessary at start-up time.  Note that we use        //
//  kCurrentProcess in our psn rather than calling GetCurrentProcess.  Using        //
//  kCurrentProcess will allow us to record those events we send to ourselves,      //
//  otherwise, the recorder won't recognize the psn and won't record our event!     //
//----------------------------------------------------------------------------------//
#pragma segment Initialize
void Initialize()
{
    Handle                  menuBar;
    long                    total, contig;
    EventRecord             event;
    short                   count;
 
    gInBackground = false;
    InitGraf((Ptr)&qd.thePort);
    InitWindows();
    InitMenus();
    InitDialogs(nil);
    InitCursor();
    InitAEHandlers();
    for (count = 1; count <= 3; count++)
        EventAvail(everyEvent, &event);
     
    SysEnvirons(kSysEnvironsVersion, &gMac);    
    if (gMac.machineType < 0) 
        SignalError(eWrongMachine);             // Less than 128K ROM's.
    gHasWaitNextEvent = IsTrapAvailable(_WaitNextEvent, ToolTrap);
     
    if ((long)GetApplLimit() - (long)ApplicationZone() < kMinHeap) 
        SignalError(eSmallSize);
    
    PurgeSpace(&total, &contig);
    if (total < kMinSpace)
        if (UnloadScrap() != noErr)
            SignalError(eNoMemory);
        else
        {
            PurgeSpace(&total, &contig);
            if (total < kMinSpace)
                SignalError(eNoMemory);
        }
 
    if (!(menuBar = GetNewMBar(rMenuBar)))      // Set up menu bar.
        SignalError(eNoMemory);
    SetMenuBar(menuBar);
    DisposeHandle(menuBar);
    AppendResMenu(GetMenuHandle(mApple), 'DRVR');           // Add DA's to menu.
    DrawMenuBar();
 
        // 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));
    gNullDesc.descriptorType = typeNull;        // Initialize the global null descriptor record.
    gNullDesc.dataHandle = nil;
 
    gRefNum = CurResFile();
    gNumWindowsOpen = 0;
    gNewWindows = 0;
}
 
//----------------------------------------------------------------------------------//
//  Returns true if the given trap number is implemented, else returns false.       //
//----------------------------------------------------------------------------------//
#pragma segment Initialize
Boolean IsTrapAvailable(short trapNum, TrapType  tType)
{
    if ((tType == (unsigned char)ToolTrap) && (gMac.machineType > envMachUnknown) &&
         (gMac.machineType < envMacII))
    {                                           // it's a 512K, Plus, or SE
        trapNum = trapNum & 0x03FF;
        if (trapNum > 0x01FF)                   // which means the tool traps
            trapNum = _Unimplemented;           // only go to 0x01FF
    }
    return(NGetTrapAddress(trapNum, tType) != GetToolTrapAddress(_Unimplemented));  // [pwpc]
}
 
//----------------------------------------------------------------------------------//
#pragma segment Initialize
void SignalError(short error)
{
    AlertUser(error);
    ExitToShell();
}
 
//**********************************************************************************//
//                  *  Apple Events and Object Model Support *                      //
//**********************************************************************************//
 
//----------------------------------------------------------------------------------//
//  Initializes all descriptor records passed in to this routine.  The variable     //
//  argument list is null terminated.                                               //
//----------------------------------------------------------------------------------//
#pragma segment Main
void MyInitDescs(AEDesc*  desc1, ... )          // Variable, null terminated argument list.
{
    va_list     argptr;                         // pointer to each argument in list.
    AEDesc*     nextDesc;                       // next descriptor argument in list.
 
    va_start(argptr, desc1);
    desc1->descriptorType = typeNull;
    desc1->dataHandle = nil;
    
    while(nextDesc = va_arg(argptr, AEDesc *))
    {
        nextDesc->descriptorType = typeNull;
        nextDesc->dataHandle = nil;
    }
    va_end(argptr);
}
    
//----------------------------------------------------------------------------------//
//  Dispose all descriptor records passed into this routine. (Variable arg. list).  //
//----------------------------------------------------------------------------------//
#pragma segment Main
void MyDisposeDescs(AEDesc*  desc1, ... )       // Null terminated argument list.
{
    va_list     argptr;         // pointer to each argument in list.
    AEDesc*     nextDesc;       // descriptor argument in list.
 
    va_start(argptr, desc1);
    if (desc1->dataHandle)
        AEDisposeDesc(desc1);
 
    while(nextDesc = va_arg(argptr, AEDesc *))
    {
        if (nextDesc->dataHandle)
            AEDisposeDesc(nextDesc);
    }
    va_end(argptr);
}
 
//----------------------------------------------------------------------------------//
//  Converts a descriptor to a boolean.                                             //
//----------------------------------------------------------------------------------//
#pragma segment AppleEvents
OSErr DescToBoolean(const AEDesc* desc, Boolean* boolvalue)
{
    AEDesc          tempDesc;
    Handle          dataHandle;
 
    tempDesc.dataHandle = nil;
    if (desc->descriptorType == typeBoolean)
        dataHandle = desc->dataHandle;
    else
        if (AECoerceDesc(desc, typeBoolean, &tempDesc) == noErr)
            dataHandle = tempDesc.dataHandle;
        else
            return(errAECoercionFail);
    
    *boolvalue = **dataHandle;
    MyDisposeDescs(&tempDesc, kEndOfList);
    return(noErr);
}
 
//----------------------------------------------------------------------------------//
//  Converts a descriptor to a long.                                                //
//----------------------------------------------------------------------------------//
#pragma segment AppleEvents
OSErr DescToLong(const  AEDesc* desc, long* longvalue)
{
    AEDesc          tempDesc;
    Handle          dataHandle;
 
    tempDesc.dataHandle = nil;
    if (desc->descriptorType == typeLongInteger)
        dataHandle = desc->dataHandle;
    else
        if (AECoerceDesc(desc, typeLongInteger, &tempDesc) == noErr)
            dataHandle = tempDesc.dataHandle;
        else
            return(errAECoercionFail);
    
    *longvalue = *(LongPtr)*dataHandle;
    MyDisposeDescs(&tempDesc, kEndOfList);
    return(noErr);
}
 
//----------------------------------------------------------------------------------//
//  Converts a descriptor to a pascal string.                                       //
//----------------------------------------------------------------------------------//
#pragma segment AppleEvents
OSErr DescToPString(const AEDesc* desc, Str255 str, short maxLength)
{
    AEDesc          tempDesc;
    Handle          dataHandle;
    long            charCount;
 
    tempDesc.dataHandle = nil;
    if (desc->descriptorType == typeChar)
        dataHandle = desc->dataHandle;
    else
        if (AECoerceDesc(desc, typeChar, &tempDesc) == noErr)
            dataHandle = tempDesc.dataHandle;
        else
            return(errAECoercionFail);
    
    charCount = GetHandleSize(dataHandle);
    if (charCount > maxLength)
    {
        MyDisposeDescs(&tempDesc, kEndOfList);
        return(errAECoercionFail);
    }
 
    str[0] = charCount;
    HLock(dataHandle);
    BlockMove(*dataHandle, &str[1], charCount);
    HUnlock(dataHandle);        // This may be from desc, so must unlock.
    MyDisposeDescs(&tempDesc, kEndOfList);
    return(noErr);
}
 
//----------------------------------------------------------------------------------//
//  Create the first window in response to the Open Application Apple Event.        //
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr HandleOpenApp(AppleEvent *theAppleEvent, AppleEvent* reply, long refCon)
{
    #pragma unused (reply,refCon)
    WindowPtr   window;
    OSErr       err;
    
    if (!(err = GetMissingParams(theAppleEvent)))       // Error if any parameters.
    {
        if (window = DoCreateNewWindow((WindowPtr)-1))  // Create initial window
            ShowWindow(window);
        else
            err = errAEEventNotHandled;
    }
    return(err);
}
 
//----------------------------------------------------------------------------------//
//  Send a Quit Application Apple Event to myself to terminate this app.            //
//----------------------------------------------------------------------------------//
#pragma segment Main
void SendQuitApp()
{
    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.
}
 
//----------------------------------------------------------------------------------//
//  Quit the application.                                                           //
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr HandleQuitApp(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
{
    #pragma unused (reply,refCon)
    OSErr   err;
    
    if (!(err = GetMissingParams(theAppleEvent)))   // Error if there are any parameters.
        Terminate();
    return(err);
}
 
//----------------------------------------------------------------------------------//
//  This routine makes a clone of the given window by copying its bounds, zoom      //
//  state, and title (with the addition of "copy") properties.                      //
//----------------------------------------------------------------------------------//
#pragma segment Main
WindowPtr DoCloneWindow(WindowPtr windowToClone, WindowPtr behindWindow)
{
    WindowPtr   clonedWindow;
    Rect        bounds;
    Str255      title;
 
    if (clonedWindow = DoCreateNewWindow(behindWindow))
    {
        GetWTitle(windowToClone, title);
        p2cstr(title);
        strcat((char *)title, " copy\0");
        c2pstr((char *)title);
        bounds = DoGetWindowBounds(windowToClone);
        SetWTitle(clonedWindow, title);
        MoveWindow(clonedWindow, bounds.left, bounds.top, false);
        SizeWindow(clonedWindow, bounds.right-bounds.left, bounds.bottom-bounds.top, true);
        SetWRefCon(clonedWindow, GetWRefCon(windowToClone));
        return(clonedWindow);
    }
    return(nil);
}
 
//----------------------------------------------------------------------------------//
//  Handle the Clone Apple Event and create a clone of the given object. To clone   //
//  a window, I clone its bounds, zoom state, and visible properties. In addition,  //
//  I clone the window's title and append " copy" to it for the cloned window's     //
//  title. If the insertion location parameter is not in the event record, I        //
//  perform the default behavior, which is to position the clone behind the         //
//  window being cloned.                                                            //
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr HandleClone(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
{
    #pragma unused (refCon)
    AEDesc      cloneObject, windowObject, replyObject, insertionLoc;
    AERecord    insertionRec;
    DescType    theType, position;
    WindowPtr   windowToClone, window, rplcWindow, behindWindow = nil;
    Size        paramSize;
    OSErr       err = noErr;
 
 
    MyInitDescs(&cloneObject,&windowObject,&replyObject,&insertionLoc,&insertionRec,kEndOfList);
        //  Let's get the direct object, the object to clone.
    if (err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeObjectSpecifier, &cloneObject))
        goto myExit;
    if (!(windowToClone = ResolveToWindow(&cloneObject)))
    {
        err = errAENoSuchObject;
        goto myExit;
    }
    else        // we have a window to clone.
    {
        if (!(err = AEGetParamDesc(theAppleEvent,keyAEInsertHere,typeInsertionLoc,&insertionLoc)))
            if (!(err = AECoerceDesc(&insertionLoc, typeAERecord, &insertionRec)))
                // Get object as typeWildCard because it may be null or an object specifier.
                if (!(err = AEGetKeyDesc(&insertionRec, keyAEObject, typeWildCard, &windowObject)))
                    if (!(err = AEGetKeyPtr(&insertionRec,keyAEPosition,typeEnumeration,&theType,
                                        (Ptr)&position,sizeof(DescType),&paramSize)))
                        err = FindRelativeWindow(&behindWindow, &windowObject, position, &rplcWindow);
 
        if (err)
            if (err == errAEDescNotFound)
                behindWindow = windowToClone;       // Registry's default behavior.
            else
                goto myExit;
    }
 
    if (window = DoCloneWindow(windowToClone, behindWindow))
    {
        if (((WindowPeek)windowToClone)->visible)
            ShowWindow(window);
        if (position == kAEReplace)
            CloseTheWindow(rplcWindow);
 
        if (reply->dataHandle != nil)
        {
            CreateWindowObjectSpec(window, kIndexKeyForm, &replyObject);
            err = AEPutParamDesc(reply, keyAEResult, &replyObject);
        }
    }
    else
        err = errAEEventNotHandled;
 
myExit:
    MyDisposeDescs(&cloneObject,&windowObject,&replyObject,&insertionLoc,&insertionRec,kEndOfList);
    return(err);
}   
 
//----------------------------------------------------------------------------------//
//  Send a Close Apple Event to myself to close the specified window.               //
//----------------------------------------------------------------------------------//
#pragma segment Main
void SendClose(WindowPtr  window)
{
    AppleEvent      myAppleEvent, reply;
    AEDesc          windowObject;               // The window object specifier.
 
                //  Create the Close Apple Event.
    FailIfErr(AECreateAppleEvent(kAECoreSuite, kAEClose, &gSelfAddress, kAutoGenerateReturnID,
                                    kAnyTransactionID, &myAppleEvent));
                //  Create the window object specifier and add this to myAppleEvent.
    CreateWindowObjectSpec(window, kIndexKeyForm, &windowObject);
    FailIfErr(AEPutParamDesc(&myAppleEvent, keyDirectObject, &windowObject));
                //  Send the Apple Event.
    FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract, kAENormalPriority,
                                kAEDefaultTimeout, nil, nil));
                //  Now dispose of the AppleEvent and object specifier.                             
    AEDisposeDesc(&myAppleEvent);
    AEDisposeDesc(&windowObject);
}
 
//----------------------------------------------------------------------------------//
//  Respond to the Close Apple Event by closing the specified window object.        //
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr HandleClose(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
{
    #pragma unused (reply,refCon)
    AEDesc          windowObject;
    WindowPtr       windowToClose;
    OSErr           myErr;
    
    MyInitDescs(&windowObject,kEndOfList);
        //  First, get the direct object which is the object to close.
    myErr = AEGetParamDesc(theAppleEvent,keyDirectObject,typeObjectSpecifier,&windowObject);
    if (!myErr && !(myErr = GetMissingParams(theAppleEvent)))
    {
        if (windowToClose = ResolveToWindow(&windowObject))
            CloseTheWindow(windowToClose);
        else
            myErr = errAENoSuchObject;
    }
    MyDisposeDescs(&windowObject,kEndOfList);
    return(myErr);
}
 
//----------------------------------------------------------------------------------//
//  Respond to the Count Elements Apple Event.                                      //
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr HandleCountElements(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
{
    #pragma unused (refCon)
    AEDesc          directObject;
    DescType        theType, theClass;
    Size            paramSize;
    OSErr           err;
    
 
    MyInitDescs(&directObject, kEndOfList);
        //  Get the direct object, should be null.
    if (!(err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeWildCard, &directObject)))
        if (!(err = AEGetParamPtr(theAppleEvent,keyAEObjectClass,typeType,&theType,(Ptr)&theClass,
                    sizeof(DescType),&paramSize)))      // Get class of elements to count.
            err = GetMissingParams(theAppleEvent);      // Error if more parameters.
 
    if (err)
        goto myExit;
        
        //  If we had a deeper object hierarchy, we'd probably call AEResolve here, but...
        //  we only handle the window class contained within the null object.
    if (theClass == cWindow && directObject.descriptorType == typeNull)
        err = AEPutParamPtr(reply, keyAEResult, typeLongInteger, (Ptr)&gNumWindowsOpen, sizeof(long));
 
myExit:
    MyDisposeDescs(&directObject, kEndOfList);
    return(err);
}
 
//----------------------------------------------------------------------------------//
//  Send a Create Element Apple Event to myself to create a new window. By default, //
//  I am setting the position to the beginning of the null container (frontmost).   //
//  In this case, as well as at the end of the container, the object parameter is   //
//  the null container. If the position is before, after, or replace, the object    //
//  parameter must be an object specifier to indicate the relative window.          //
//----------------------------------------------------------------------------------//
#pragma segment Main
void SendCreateElement()
{
    AppleEvent      myAppleEvent, reply;
    AERecord        insertionRec;                   // Insertion Loc record.
    AEDesc          insertionLoc;                   // The coerced insertionRec.
    DescType        theType;
    
                //  Create the Apple Event.
    FailIfErr(AECreateAppleEvent(kAECoreSuite, kAECreateElement, &gSelfAddress, kAutoGenerateReturnID,
                                    kAnyTransactionID, &myAppleEvent));
                //  Attach the class of the new element, which in this case is cWindow.
    theType = cWindow;
    FailIfErr(AEPutParamPtr(&myAppleEvent, keyAEObjectClass, typeType, (Ptr)&theType, sizeof(DescType)));
 
                //  Create insertion loc, object is null container and position is beginning.
    FailIfErr(AECreateList(nil, 0, true, &insertionRec));           // Create an AE Record.
    theType = kAEBeginning;
    FailIfErr(AEPutKeyDesc(&insertionRec, keyAEObject, &gNullDesc));
    FailIfErr(AEPutKeyPtr(&insertionRec, keyAEPosition, typeEnumeration, (Ptr)&theType, sizeof(DescType)));
    FailIfErr(AECoerceDesc(&insertionRec, typeInsertionLoc, &insertionLoc));
                // Now add the insertion location descriptor record to the Apple Event.
    FailIfErr(AEPutParamDesc(&myAppleEvent, keyAEInsertHere, &insertionLoc));
                //  Send the Apple Event.
    FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract, kAENormalPriority,
                                kAEDefaultTimeout, nil, nil));
                //  Now dispose of the AppleEvent and other records.
    MyDisposeDescs(&myAppleEvent, &insertionRec, &insertionLoc, kEndOfList);
}
 
//----------------------------------------------------------------------------------//
//  Respond to the Create Element Apple event and create a new window. For this     //
//  application, the keyAEInsertHere parameter is optional. If this parameter is    //
//  not present, a new window is created in the frontmost position.                 //
//  This routine also handles the optional initial data parameters (keyAEData and   //
//  keyAEPropData) if they are present. A window object specifier must be in the    //
//  keyAEData parameter, which is essentially used to make a clone. If the          //
//  property data exists, these properties will override those previously set.      //
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr HandleCreateElement(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
{
    #pragma unused (refCon)
    AEDesc          windowObject, dataObject, propData, propObject, replyObject;
    AEDesc          insLocParam;
    AERecord        insLocRec;
    AERecord        dataPropParam;                  // Initial data parameters.
    AEKeyword       keyWord;                        // Property id code for PropData.
    DescType        theType, theClass, position;
    WindowPtr       window, relativeWindow, dataWindow, rplcWindow;
    Rect            bounds;
    Size            theSize;
    Str255          buffer;
    long            numItems;
    short           i;
    Boolean         isVisible;
    OSErr           err;
    
    if (err = AEGetParamPtr(theAppleEvent, keyAEObjectClass, typeType, &theType, (Ptr)&theClass,
                    sizeof(DescType), &theSize))
        return(err);
    if (theClass != cWindow)            // We only handle elements of the class cWindow.
        return(errAEEventNotHandled);
    position = typeNull;
    MyInitDescs(&windowObject,&dataObject,&propData,&propObject,&insLocParam,&dataPropParam,&replyObject,&insLocRec,kEndOfList);
            // Now get the insertion location record as an AERecord, if it exists.
    if (!(err = AEGetParamDesc(theAppleEvent, keyAEInsertHere, typeInsertionLoc, &insLocParam)))
    {       // coerce the insertion loc record to an AE record.
        err = AECoerceDesc(&insLocParam, typeAERecord, &insLocRec);
            //  Get the object as typeWildCard because it may be a null descriptor or an object.
        if (!(err = AEGetKeyDesc(&insLocRec, keyAEObject, typeWildCard, &windowObject)))
            if (!(err = AEGetKeyPtr(&insLocRec, keyAEPosition, typeEnumeration, &theType, (Ptr)&position,
                        sizeof(DescType), &theSize)))
            {
                relativeWindow = nil;
                err = FindRelativeWindow(&relativeWindow, &windowObject, position, &rplcWindow);
            }
    }
    else
        if (err == errAEDescNotFound)   // No insertion loc, make it frontmost by default.
        {
            relativeWindow = (WindowPtr)-1;
            position = kAEBeginning;
            err = noErr;        // Not an error for me because I make this param optional.
        }
 
    if (err)
        goto myExit;
        
                // Check if optional data parameter is present.
    if (!(err = AEGetParamDesc(theAppleEvent,keyAEData,typeObjectSpecifier,&dataObject)))
    {
        if (dataWindow = ResolveToWindow(&dataObject))
        {
            window = DoCloneWindow(dataWindow, relativeWindow);
            isVisible = ((WindowPeek)dataWindow)->visible;
        }
        else
        {
            err = errAENoSuchObject;
            goto myExit;
        }
    }
    else
        if (err == errAEDescNotFound)   // The optional data parameter is not present.
        {
            if (window = DoCreateNewWindow(relativeWindow))
            {
            err = noErr;
            isVisible = true;
                if (position == kAEReplace)         // Replace the window in the right position.
                {
                    bounds = DoGetWindowBounds(rplcWindow);
                    MoveWindow(window, bounds.left, bounds.top, false);
                }
            }
            else
            {
                err = errAEEventNotHandled;     // couldn't create a new window.
                goto myExit;
            }
        }
        else
            goto myExit;
 
    if (isVisible)                  // We set the visibility here because it may be changed
        ShowWindow(window);         // by the following property data.
 
            // Handle PropData parameter if it exists.      
    if (!(err = AEGetParamDesc(theAppleEvent,keyAEPropData,typeAERecord,&dataPropParam)))
    {
        AECountItems(&dataPropParam, &numItems);
        for (i = 1; i <= numItems; i++)
        {
            if (!(err = AEGetNthPtr(&dataPropParam,i,typeWildCard,&keyWord,&theType,&buffer,sizeof(Str255),&theSize)))
            {
                AECreateDesc(keyWord, (Ptr)&window, sizeof(Ptr), &propObject);
                AECreateDesc(theType, (Ptr)&buffer, theSize, &propData);
                err = DoSetData(&propObject, &propData);
                AEDisposeDesc(&propObject);
                AEDisposeDesc(&propData);
                if (err)
                    break;
            }
        }
    }
    
    if (!err || err == errAEDescNotFound)
    {
        if (position == kAEReplace)
            CloseTheWindow(rplcWindow);
        err = noErr;
        if (reply->dataHandle != nil)
        {
            CreateWindowObjectSpec(window, kIndexKeyForm, &replyObject);
            err = AEPutParamDesc(reply, keyAEResult, &replyObject);
        }
    }
        
myExit:
    MyDisposeDescs(&windowObject,&dataObject,&propData,&propObject,&insLocParam,&dataPropParam,&replyObject,&insLocRec,kEndOfList);
    return(err);
}
 
//----------------------------------------------------------------------------------//
//  Respond to the Do Objects Exist AE by attempting to resolve the object specifier//
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr HandleDoObjectsExist(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
{
    #pragma unused (reply,refCon)
    AEDesc      target, token;
    Boolean     exists;
    OSErr       err;
    
    MyInitDescs(&target, &token, kEndOfList);
    if (!(err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeWildCard, &target)))
        if (!(err = GetMissingParams(theAppleEvent)))           // Check for missing params.
        {
            exists = true;
            token.descriptorType = typeNull;
            if (target.descriptorType != typeNull)
                exists = (AEResolve(&target, kAEIDoMinimum, &token) == noErr);
 
                //  Add data to the reply Apple event record.
            err = AEPutParamPtr(reply, keyDirectObject,typeBoolean,(Ptr)&exists,sizeof(Boolean));
        }
myExit:
    MyDisposeDescs(&target, &token, kEndOfList);
    return(err);
}
 
//----------------------------------------------------------------------------------//
//  Send the Set Data Apple Event with the object, property, and property data.     //
//  *NOTE*: I am sending myself the Set Data event in response to user interaction. //
//  These actions have already occurred by this time, so I am sending the event     //
//  with the "don't execute" flag set for "smart" recorders.  A "smart" recorder    //
//  would check this flag when it intercepts the Apple event, and if it was set,    //
//  it wouldn't pass the event to the application.                                  //
//----------------------------------------------------------------------------------//
#pragma segment Main
void SendSetData( AEDesc*   propDesc,           // the property to set
                  AEDesc*   propData,           // the property data
                  AEDesc*   target  )       // object to set property of
{
    AppleEvent  myAppleEvent, reply;
    AEDesc      objectToSet;
 
    FailIfErr(AECreateAppleEvent(kAECoreSuite, kAESetData, &gSelfAddress, kAutoGenerateReturnID,
                                    kAnyTransactionID, &myAppleEvent));
                //  Create the object specifier for the property of the object.
    FailIfErr(CreateObjSpecifier(cProperty, target, formPropertyID, propDesc, 
                                        false, &objectToSet));
                //  Attach the property object specifier.
    FailIfErr(AEPutParamDesc(&myAppleEvent, keyDirectObject, &objectToSet));
                //  Add the property data.
    FailIfErr(AEPutParamDesc(&myAppleEvent, keyAEData, propData));
    FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract+kAEDontExecute, kAENormalPriority,
                                kAEDefaultTimeout, nil, nil));
 
    AEDisposeDesc(&objectToSet);                    // Clean up.                                
    AEDisposeDesc(&myAppleEvent);
}
 
//----------------------------------------------------------------------------------//
//  To set the data of an object, the expected data is passed in its raw form with  //
//  the property type in the descriptorType field and the data in the dataHandle.   //
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr HandleSetData(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
{
    #pragma unused (reply,refCon)
    AEDesc      target, data, token;
    OSErr       err;
    
    MyInitDescs(&target, &data,&token, kEndOfList);
        //  First, get the direct object. This is the object whose data is to be set.
    if (!(err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeObjectSpecifier, &target)))
        if (!(err = AEResolve(&target, kAEIDoMinimum, &token)))     // Resolve it.
           if (!(err = AEGetParamDesc(theAppleEvent, keyAEData, typeWildCard, &data)))
              err = DoSetData(&token, &data);
    MyDisposeDescs(&target, &data, &token, kEndOfList);
    return(err);
}
 
//----------------------------------------------------------------------------------//
//  Return a reply to the Get Data or Get Data Size Apple Event for the requested   //
//  data. The refcon parameter is used to distinguish the two events. If typeBest   //
//  is the requested return type, the data's descriptor type is the result type.    //
//  **NOTE: Do not use the same descriptor as source and dest in AECoerceDesc().    //
//  This routine creates a copy of the source, and then it is impossible to dispose //
//  of the memory originally contained in the source's dataHandle.                  //
//  2/25/92 - Removed FailIfErr calls. Now the error is returned as a result.       //
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr HandleGetData( AppleEvent*    theAppleEvent,
                     AppleEvent*    reply,
                     long           refCon  )       // kAEGetData or kAEGetDataSize.
{
    AEDesc          theObject, token;               // direct object and resolved token.
    AEDesc          objectData, tempDesc;           // object data, and coerced data.
    DescType        reqType;
    WindowPtr       window;
    Size            theSize;
    OSErr           err;
    
    MyInitDescs(&theObject, &objectData, &token, kEndOfList);
            //  First, get the direct objet.
    if (err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeObjectSpecifier, &theObject))
        goto myExit;
            //  Next, get the requested return type, if it exists.
    if (err = AEGetParamPtr(theAppleEvent, keyAERequestedType, typeType, &reqType,
                                (Ptr)&reqType, sizeof(DescType), &theSize))
    {
        if (err == errAEDescNotFound)       // not an error if return type is not found
        {
            err = noErr;
            reqType = typeWildCard;
        }
        else
            goto myExit;
    }
    if (err = GetMissingParams(theAppleEvent))          // check for missing params
        goto myExit;
 
            //  Resolve the object specifier and get the token containing the property and container.
    if (!(err = AEResolve(&theObject, kAEIDoMinimum, &token)))
        if (window = (WindowPtr)*(LongPtr)*token.dataHandle)        // Nil for application; WindowPtr for window
            err = GetWindowData(token.descriptorType, window, &objectData);
        else
            err = GetAppData(token.descriptorType, &objectData);
 
    if (err == noErr && reply->dataHandle != nil)
    {       //  Add data to the reply Apple event record.
        if (reqType != typeWildCard && reqType != typeBest &&
            reqType != objectData.descriptorType)
        {
            err = AECoerceDesc(&objectData, reqType, &tempDesc);
            MyDisposeDescs(&objectData, kEndOfList);
            objectData.descriptorType = tempDesc.descriptorType;
            objectData.dataHandle = tempDesc.dataHandle;
        }
        if (!err)
        {
            if (refCon == kAEGetData)               // return data
                err = AEPutParamDesc(reply, keyAEResult, &objectData);
            else if (refCon == kAEGetDataSize)      // return data size
            {
                theSize = GetHandleSize(objectData.dataHandle);
                err = AEPutParamPtr(reply, keyAEResult, typeLongInteger, (Ptr)&theSize, sizeof(long));
            }
        }
    }
    
myExit:
    MyDisposeDescs(&theObject, &objectData, &token, kEndOfList);
    return(err);
}
 
//----------------------------------------------------------------------------------//
//  Send a Move Apple event to myself in response to a user selecting a window      //
//  and making it frontmost. This event is sent with the insertion location record  //
//  specifying the beginning of the null container. If the index is non-zero, this  //
//  indicates that the move event has already been performed by DragWindow(). Thus, //
//  this event is passed with the don't execute flag set.                           //
//----------------------------------------------------------------------------------//
#pragma segment Main
void SendMoveEvent(WindowPtr windowToMove, long index)
{
    AppleEvent      myAppleEvent, reply, windowObject;
    AERecord        insertionRec;                   // Insertion Loc record.
    AEDesc          insertionLoc;                   // The coerced insertionRec.
    DescType        theType;
    
        //  Create the Apple Event.
    FailIfErr(AECreateAppleEvent(kAECoreSuite, kAEMove, &gSelfAddress, kAutoGenerateReturnID,
                                    kAnyTransactionID, &myAppleEvent));
        //  Create the object spec for the window to move.
    FailIfErr(CreateWindowObjectSpec(windowToMove, kIndexKeyForm, &windowObject));
    FailIfErr(AEPutParamDesc(&myAppleEvent, keyDirectObject, &windowObject));
 
        //  Create insertion loc record for beginning of null container.
    FailIfErr(AECreateList(nil, 0, true, &insertionRec));           // Create an AE Record.
    theType = kAEBeginning;
    FailIfErr(AEPutKeyDesc(&insertionRec, keyAEObject, &gNullDesc));
    FailIfErr(AEPutKeyPtr(&insertionRec,keyAEPosition,typeEnumeration,(Ptr)&theType,sizeof(DescType)));
    FailIfErr(AECoerceDesc(&insertionRec, typeInsertionLoc, &insertionLoc));
        // Now add the insertion location descriptor record to the Apple Event.
    FailIfErr(AEPutParamDesc(&myAppleEvent, keyAEInsertHere, &insertionLoc));
        //  Send the Apple Event.
    if (index)
        FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract+kAEDontExecute,
                            kAENormalPriority, kAEDefaultTimeout, nil, nil));
    else
        FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract,
                            kAENormalPriority, kAEDefaultTimeout, nil, nil));
 
        //  Now dispose of the AppleEvent and other records.
    MyDisposeDescs(&myAppleEvent,&windowObject,&insertionRec,&insertionLoc,kEndOfList);
}
 
//----------------------------------------------------------------------------------//
//  Respond to the Move Apple Event by reordering the window list.  For CoreSample, //
//  the keyAEInsertHere parameter is optional. If this parameter does not exist,    //
//  the specified window will move the  to the front.                               //
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr HandleMove(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
{
    #pragma unused (refCon)
    AEDesc          object, windowObj, replyObj, insertionLoc;
    AERecord        insertionRec;
    DescType        theType, position;
    WindowPtr       windowToMove, relativeWindow, rplcWindow;
    Rect            bounds;
    Size            paramSize;
    OSErr           err;
    
    MyInitDescs(&object,&windowObj,&insertionLoc,&insertionRec,&replyObj,kEndOfList);
        //  First, get the direct parameter, the object to move.
    if (err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeObjectSpecifier, &object))
        goto myExit;
    if (!(windowToMove = ResolveToWindow(&object)))         // Check if valid window object.
    {
        err = errAENoSuchObject;
        goto myExit;
    }
 
        // Retrieve the insertion location record, if it exists.
    if ((err = AEGetParamDesc(theAppleEvent,keyAEInsertHere,typeInsertionLoc,&insertionLoc)) == errAEDescNotFound)
    {           // Execute *MY* default behavior since insertion loc param not present.
        SelectWindow(windowToMove);
        err = noErr;
        goto myExit;
    }
    else
        if (err)
            goto myExit;
        else            // get data from insertion loc and coerce it to typeAERecord.
        {
            if ((err = GetMissingParams(theAppleEvent))  ||
                (err = AECoerceDesc(&insertionLoc, typeAERecord, &insertionRec)) || 
                (err = AEGetKeyDesc(&insertionRec,keyAEObject,typeWildCard,&windowObj)) ||
                (err = AEGetKeyPtr(&insertionRec,keyAEPosition,typeEnumeration,&theType,
                                    (Ptr)&position,sizeof(DescType),&paramSize)))
                    goto myExit;
        }
 
    if (!(err = FindRelativeWindow(&relativeWindow,&windowObj,position,&rplcWindow)))
    {
        if (position == kAEReplace)
            if (windowToMove == rplcWindow)
                goto myExit;                // do nothing.
            else
            {
                bounds = DoGetWindowBounds(rplcWindow);
                CloseTheWindow(rplcWindow);
                MoveWindow(windowToMove, bounds.left, bounds.top, false);
            }
 
        if (relativeWindow == (WindowPtr)-1)        // [pwpc]
            SelectWindow(windowToMove);
        else
            if (windowToMove != relativeWindow)
                SendBehind(windowToMove, relativeWindow);       // NOTE: may have to call PaintOne and
                                                                // CalcVis if after; see IM I-286
        if (position == kAEReplace && windowToMove != rplcWindow)
        {
            bounds = DoGetWindowBounds(rplcWindow);
            CloseTheWindow(rplcWindow);
            MoveWindow(windowToMove, bounds.left, bounds.top, false);
        }
    }
 
myExit:
    if (!err)
        if (reply->dataHandle != nil)
        {
            CreateWindowObjectSpec(windowToMove, kIndexKeyForm, &replyObj);
            err = AEPutParamDesc(reply, keyAEResult, &replyObj);
        }
    MyDisposeDescs(&object,&windowObj,&insertionLoc,&insertionRec,&replyObj,kEndOfList);
    return(err);
}
 
//----------------------------------------------------------------------------------//
//  Set up the descriptor records needed to set the data for the bounds, position,  //
//  and zoomed properties.  The bounds is set in response to sizing a window; the   //
//  position is set after dragging a window; and the isZoomed property is set when  //
//  zooming a window in or out.                                                     //
//----------------------------------------------------------------------------------//
#pragma segment Main
void SetUpPropertyData( WindowPtr       window,         // Window object.
                        DescType        propType,       // Property descriptor type.
                        DescType        dataType,       // Descriptor type for data.
                        Size            dataSize   )    // Size of data.
{
    AEDesc      windowObject, theData, theProperty;
    Rect        bounds;
    Boolean     isZoomed;
    
    MyInitDescs(&windowObject, &theData, &theProperty, kEndOfList);
    if (propType == pIsZoomed)
    {
        isZoomed = (Boolean)GetWRefCon(window);
        FailIfErr(AECreateDesc(dataType,(Ptr)&isZoomed,dataSize,&theData));
    }
    else        // it's either pBounds or pPosition.
    {
        bounds = DoGetWindowBounds(window);
        FailIfErr(AECreateDesc(dataType, (Ptr)&bounds, dataSize, &theData));
    }
        
    CreateWindowObjectSpec(window, kIndexKeyForm, &windowObject);
    FailIfErr(AECreateDesc(typeType, (Ptr)&propType, sizeof(DescType), &theProperty));
 
    SendSetData(&theProperty, &theData, &windowObject);
    MyDisposeDescs(&windowObject, &theData, &theProperty, kEndOfList);
}
 
//----------------------------------------------------------------------------------//
//  Set the property data for the specified object.  For now, we only handle window //
//  objects, and you may only set the modifiable properties (defined in Registry).  //
//  *NOTE*:  We do not allow the application's properties to be modified.           //
//----------------------------------------------------------------------------------//
#pragma segment Main
OSErr DoSetData( AEDesc*    token,              // Contains the property and object.
                 AEDesc*    data    )           // Contains the data to set.
{
    AEDesc          propData;           // Property data.
    Rect            bounds;
    GrafPtr         oldPort;
    WindowPtr       window, behindWindow;
    Str255          name;
    long            newIndex;
    short           part;
    Boolean         value;
    Point           pt;
    OSErr           err;
 
    err = noErr;
    if (window = (WindowPtr)*(LongPtr)*(token->dataHandle))
    {
        GetPort(&oldPort);
        switch (token->descriptorType)
        {
            case pBounds:
                if (data->descriptorType != typeQDRectangle)
                {
                    propData.dataHandle = nil;
                    err = AECoerceDesc(data, typeQDRectangle, &propData);
                    bounds = *(Rect *)*propData.dataHandle;     // Get content region.
                    MyDisposeDescs(&propData, kEndOfList);
                }
                else
                    bounds = *(Rect *)*data->dataHandle;        // Get content region.
        
                if (!err)
                {
                    SetPort(window);
                    InvalRect(&window->portRect);
        
                        // Real applications may want to make a sanity check on the new bounds.     
                    MoveWindow(window, bounds.left, bounds.top, false);
                    SizeWindow(window, bounds.right-bounds.left, bounds.bottom-bounds.top, true);
                    InvalRect(&window->portRect);
                }
                break;
            
            case pIndex:
                if (DescToLong(data,&newIndex) != noErr)
                    return(errAECoercionFail);      // Data cannot be coerced.
 
                if (newIndex > gNumWindowsOpen)
                    err = errAEIndexTooLarge;
                else
                {
                    if (newIndex == 1)
                        SelectWindow(window);
                    else
                        if (behindWindow = GetWindowAtIndex(newIndex))
                            SendBehind(window, behindWindow);
                        else
                            err = errAEEventFailed;
                }
                break;
                
            case pIsZoomed:
                if (DescToBoolean(data,&value) != noErr)
                    return(errAECoercionFail);          // Data cannot be coerced.
                    
                part = value ? inZoomOut : inZoomIn;
                ZoomIt(window, part);
                break;
 
            case pName:
                if (DescToPString(data,name,kMaxStrSize) != noErr)
                    return(errAECoercionFail);
                SetWTitle(window, name);
                break;
            
            case pPosition:
                if (data->descriptorType != typeQDPoint)
                {
                    propData.dataHandle = nil;
                    err = AECoerceDesc(data, typeQDPoint, &propData);
                    pt = *(Point *)*propData.dataHandle;
                    MyDisposeDescs(&propData, kEndOfList);
                }
                else
                    pt = *(Point *)*data->dataHandle;
 
                if (!err)
                {
                        // Real applications may want to make a sanity check on the new loc.
                    SetPort(window);
                    MoveWindow(window, pt.h, pt.v, false);
                    InvalRect(&window->portRect);
                }
                break;
            
            case pVisible:
                if (DescToBoolean(data,&value) != noErr)
                    return(errAECoercionFail);      // Data cannot be coerced.
                if (value)
                    ShowWindow(window);
                else
                    HideWindow(window);
                break;
                
            default:                        // No other properties are modifiable.
                return(errAENotModifiable);
        }
        SetPort(oldPort);
    }
    else
        return(errAEEventFailed);
    return(err);
}
 
//----------------------------------------------------------------------------------//
//  This is a dummy handler that receives Apple events which I don't handle.  It    //
//  is mainly provided as a stub in order to support all the events in the          //
//  required suite, as well as the entire core suite.  This is the handler for the  //
//  Open Document and Print Document events (required suite); and the Save, Get     //
//  Class Info, and Get Event Info events (core suite).  The Get Class Info and Get //
//  Event Info events "MAY" be supported internally in the future, so applications  //
//  will not need to handle these events themselves.  This support may be provided  //
//  since it would be consistent across all applications, and the information may   //
//  be retrieved from the 'aeut'/'aete' resources.                                  //
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr DummyHandler( AppleEvent      *theAppleEvent,
                    AppleEvent      *reply,
                    long            refCon  )
{
    #pragma unused (theAppleEvent,reply,refCon)
    return(errAEEventNotHandled);
}
 
//----------------------------------------------------------------------------------//
//  Locate the window that is relative to the specified window object at the        //
//  insertion position.  If the location is replace, the window to replace is       //
//  closed, and its bounds are returned to the calling routine.                     //
//  **Note**: if windowObj is used within this routine, the object param will       //
//  contain the same dataHandle. This will be disposed of by the calling routine.   //
//----------------------------------------------------------------------------------//
#pragma segment Main
OSErr FindRelativeWindow( WindowPtr*    relativeWindow, // window before insertion loc.
                          AEDesc*       object,         // object to be relative to.
                          DescType      position,           // insertion position.
                          WindowPtr*    replaceWindow ) // window to replace.
{
    AEDesc      windowObj;                  // Coerced descriptor.
    WindowPtr   windowToReplace;
    long        index;
    OSErr       err;
    
    err = noErr;
    *replaceWindow = nil;
    switch(position)
    {
        case kAEBeginning:                      // The object should be the container.
            if (object->descriptorType == typeNull)
                *relativeWindow = (WindowPtr)-1;
            else
                err = errAENoSuchObject;
            break;
        
        case kAEEnd:                            // The object should be the container.
            if (object->descriptorType == typeNull)
                *relativeWindow = nil;
            else
                err = errAENoSuchObject;
            break;
            
        case kAEBefore:                         // The object should be an object specifier.
        case kAEReplace:
            if (object->descriptorType != typeObjectSpecifier)
            {
                err = AECoerceDesc(object, typeObjectSpecifier, &windowObj);
                MyDisposeDescs(object, kEndOfList);
                object->descriptorType = windowObj.descriptorType;
                object->dataHandle = windowObj.dataHandle;
            }
            
            if (!err)
                if (windowToReplace = ResolveToWindow(object))
                {
                    index = GetWindowIndexNum(windowToReplace);
                    *relativeWindow = (index==1) ? (WindowPtr)-1 : GetWindowAtIndex(index-1);
                    if (position == kAEReplace)
                        *replaceWindow = windowToReplace;
            }
            else            // We weren't able to resolve the object specifier to a window.
                err = errAENoSuchObject;
            break;
            
        case kAEAfter:                      // The object should be an object specifier.
            if (object->descriptorType != typeObjectSpecifier)
            {
                err = AECoerceDesc(object,typeObjectSpecifier,&windowObj);
                MyDisposeDescs(object, kEndOfList);
                object->descriptorType = windowObj.descriptorType;
                object->dataHandle = windowObj.dataHandle;
            }
 
            if (!err)
                if (!(*relativeWindow = ResolveToWindow(object)))
                    err = errAENoSuchObject;
            break;
            
        default:
            return(errAEEventNotHandled);
    }
    return(err);
}
 
//----------------------------------------------------------------------------------//
//  Retrieves the data for the specified property of the window.  The result token  //
//  contains the type of the data in the descriptorType field, and the data itself  //
//  in the dataHandle field.  I know my application's window properties             //
//  (i.e., has title bar, has close box, is zoomable, etc.), so I set up the        //
//  result token accordingly.  If your application handles various window types,    //
//  you may need to look at the window defproc to determine which type of window it //
//  is.  If the property is pBestType or pDefaultType, I return an object specifier//
//  for the window which may be used to easily reference it.                        //
//----------------------------------------------------------------------------------//
#pragma segment Main
OSErr GetWindowData( DescType       theProperty,        // Window property.
                     WindowPtr      window,
                     AEDesc         *result )           // Contains the result upon return.
{
    DescType        theType;
    Str255          title;
    Rect            bounds;
    long            index;
    Boolean         myAnswer;
 
    switch (theProperty)
    {
        case pBestType:
        case pDefaultType:
            return(CreateWindowObjectSpec(window, kIndexKeyForm, result));
 
        case pBounds:
            bounds = DoGetWindowBounds(window);
            return(AECreateDesc(typeQDRectangle, (Ptr)&bounds, sizeof(Rect), result));
            
        case pClass:
            theType = cWindow;
            return(AECreateDesc(typeType, (Ptr)&theType, sizeof(DescType), result));
 
        case pIndex:
            index = GetWindowIndexNum(window);
            return(AECreateDesc(typeLongInteger, (Ptr)&index, sizeof(long), result));
                
        case pName:
            GetWTitle(window, title);
            return(AECreateDesc(typeChar, (Ptr)&title[1], title[0], result));
 
        case pPosition:
            bounds = DoGetWindowBounds(window);
            return(AECreateDesc(typeQDPoint, (Ptr)&bounds, sizeof(Point), result));
 
        case pHasCloseBox:
        case pHasTitleBar:
        case pIsResizable:
        case pIsZoomable:
            myAnswer = true;
            return(AECreateDesc(typeBoolean, (Ptr)&myAnswer, sizeof(Boolean), result));
 
        case pIsFloating:
        case pIsModal:
            myAnswer = false;
            return(AECreateDesc(typeBoolean, (Ptr)&myAnswer, sizeof(Boolean), result));
            
        case pIsZoomed:
            myAnswer = GetWRefCon(window);
            return(AECreateDesc(typeBoolean, (Ptr)&myAnswer, sizeof(Boolean), result));
        
        case pVisible:                  // Must check this because it is modifiable.
            myAnswer = ((WindowPeek)window)->visible;
            return(AECreateDesc(typeBoolean, (Ptr)&myAnswer, sizeof(Boolean), result));
 
        case pSelection:                // No selection in CoreSample.
            return(errAENoSuchObject);
 
        default:                        // We don't handle requested property.
            return(errAEEventNotHandled);
    }
}
 
//----------------------------------------------------------------------------------//
//  Get the property data for the application and return it in the result parameter.//
//  The result token contains the property type in the descriptorType field, and    //
//  a nil value in the dataHandle field to represent the null application.          //
//----------------------------------------------------------------------------------//
#pragma segment Main
OSErr GetAppData(   DescType    theProperty,
                    AEDesc*     result  )       // Descriptor record to hold the property data.
{
    ProcessInfoRec          myProcessInfo;      // [pwpc]
    DescType                theType;
    short                   refNum;
    Str255                  name;
    Handle                  myHandle;
    ProcessSerialNumber     thePSN, currentProcess;
    Boolean                 isFront;
    OSErr                   err;
 
    switch (theProperty)
    {
        case pBestType:                 // Return the null descriptor representing
        case pDefaultType:              // the application.
            return(AEDuplicateDesc(&gNullDesc, result));
 
        case pClass:
            theType = cApplication;
            return(AECreateDesc(typeType,(Ptr)&theType,sizeof(DescType),result));
            
        case pName:
            // [pwpc] Clear out the name, and then call the process manager to get
            // the string for the name of our application.
            
            name[0] = 0;
            myProcessInfo.processInfoLength = sizeof(myProcessInfo); 
            myProcessInfo.processName = name;
            myProcessInfo.processAppSpec = NULL;
            
            GetCurrentProcess(&currentProcess);
            GetProcessInformation(&currentProcess, &myProcessInfo);
        
            // Create an AEDesc returning the application name string
            // returned by the process manager.
 
            return(AECreateDesc(typeChar, (Ptr)&name[1], name[0], result));
 
        case pIsFrontProcess:
            GetFrontProcess(&thePSN);
            SameProcess(&gSelfPSN, &thePSN, &isFront);
            return(AECreateDesc(typeBoolean,(Ptr)&isFront,sizeof(Boolean),result));
            
        case pVersion:
            refNum = CurResFile();          // save current resource
            UseResFile(gRefNum);            // set this resource to be current
            myHandle = (Handle)Get1Resource((ResType)'vers', 1);
            HLock(myHandle);
            err = AECreateDesc(typeVersion, *myHandle, GetHandleSize(myHandle), result);
            HUnlock(myHandle);
            UseResFile(refNum);             // reset back to resource previously set
            return(err);
 
        default:                // We don't handle the requested property.
            return(errAEEventNotHandled);
    }
}
 
//----------------------------------------------------------------------------------//
//  Create an object specifier for the window with the indicated key form.          //
//----------------------------------------------------------------------------------//
#pragma segment Main
OSErr CreateWindowObjectSpec( WindowPtr window,
                              short     keyForm,        // index or name key form.
                              AEDesc*   objectSpec )    // Resulting object specifier.
{
    AEDesc      data;
    Str255      title;
    long        index;
    OSErr       err;
 
    MyInitDescs(&data, kEndOfList);
    switch(keyForm)
    {
        case kNameKeyForm:                  // Object specifier with name.
            GetWTitle(window, title);
            if (!(err = AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data)))               
                err = CreateObjSpecifier(cWindow, &gNullDesc, formName, &data,
                                    false, objectSpec);
            break;
            
        case kIndexKeyForm:                 // Object specifier with index.
            index = GetWindowIndexNum(window);
            if (!(err = CreateOffsetDescriptor(index, &data)))
                err = CreateObjSpecifier(cWindow, &gNullDesc, formAbsolutePosition, &data,
                                    false, objectSpec);
            break;
    }
    MyDisposeDescs(&data, kEndOfList);
    return(err);
}
 
//----------------------------------------------------------------------------------//
//  Check to see if there exists any additional parameters in the Apple Event.      //
//  If so, return an error to the calling routine.                                  //
//----------------------------------------------------------------------------------//
#pragma segment Main
OSErr GetMissingParams(AppleEvent*  theAppleEvent)
{
    DescType    theType;
    Size        actualSize;
    OSErr       err;
    
    err = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard,
                                &theType, nil, 0, &actualSize);
    if (err == errAEDescNotFound)
        return(noErr);
    else
        return(errAEEventNotHandled);
}
 
//----------------------------------------------------------------------------------//
//  If a reply is expected, the error number is returned in the reply parameter.    //
//----------------------------------------------------------------------------------//
#pragma segment Main
void ReportError( AppleEvent*   reply,
                  long          err )
{
    if (reply->dataHandle != nil && err != noErr)
        FailIfErr(AEPutParamPtr(reply,keyErrorNumber,typeLongInteger,(Ptr)&err,sizeof(long)));
}
 
//----------------------------------------------------------------------------------//
//  This routine returns the window object contained in the given object specifier. //
//  If the resolution does not return a descriptor record of type cWindow, nil is   //
//  returned as a result.                                                           //
//----------------------------------------------------------------------------------//
#pragma segment Main
WindowPtr ResolveToWindow(AEDesc*  objectSpecifier)
{
    AEDesc      token;
    WindowPtr   window;
 
 
    MyInitDescs(&token, kEndOfList);
    window = nil;
    if (objectSpecifier->descriptorType == typeObjectSpecifier)
        if (!(AEResolve(objectSpecifier, kAEIDoMinimum, &token)))
            if (token.descriptorType == cWindow)
                window = (WindowPtr)*((LongPtr)*(token.dataHandle));
 
    MyDisposeDescs(&token, kEndOfList);
    return(window);
}
 
//----------------------------------------------------------------------------------//
//  Retrieve the window from the null container by the key form and return its      //
//  pointer in the dataHandle field of resultToken.                                 //
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr WindowAccessor( DescType      classWanted,        // window class
                      AEDesc*       container,          // the application (null container)
                      DescType      containerClass, 
                      DescType      keyform,
                      AEDesc*       selectionData,
                      AEDesc*       resultToken,        // specified window is returned in result
                      long          theRefCon   )
{
    #pragma unused (classWanted,container,containerClass,theRefCon)
    WindowPtr       window;
    DescType        seldataType;
    Str255          title;
    long            index;
    OSErr           err;
 
    window = nil;
    err = noErr;    
    if (!gNumWindowsOpen)
        return(errAENoSuchObject);
    else
    {
        seldataType = selectionData->descriptorType;
    
        switch(keyform)
        {
            case formName:                                  // Window title.
                if (DescToPString(selectionData,title,kMaxStrSize) != noErr)
                    return(errAECoercionFail);
                if (!(window = GetWindowWithTitle(title)))
                    return(errAENoSuchObject);      // Window was not found.
                break;
            
            case formAbsolutePosition:
                if (DescToLong(selectionData,&index) != noErr)
                    return(errAECoercionFail);      // Data cannot be coerced.
                if (!(window = GetWindowAtIndex(index)))
                    return(errAENoSuchObject);          // Window was not found.
                break;  
            
            default:                                    // I don't handle any other key forms.
                return(errAEEventNotHandled);
        }
    }
    return(AECreateDesc(cWindow, (Ptr)&window, sizeof(Ptr), resultToken));
}
 
//----------------------------------------------------------------------------------//
//  Return a token representing the property for the containing window.  The token  //
//  is returned with the property and window pointer.                               //
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr WindowPropertyAccessor( DescType      classWanted,        // Property class
                              AEDesc*       container,          // Window object
                              DescType      containerClass, 
                              DescType      form,
                              AEDesc*       selectionData,
                              AEDesc*       resultToken,
                              long          theRefCon   )
{
    #pragma unused (containerClass, theRefCon)
    Ptr             window;
    DescType        propType;
    
            //  Let's make sure we're accessing a valid descriptor type.
    if ((classWanted != cProperty) || (form != formPropertyID))
        return(errAEWrongDataType);
 
    window = (Ptr)*(LongPtr)*(container->dataHandle);       // Get the window pointer.
    propType = *(LongPtr)*selectionData->dataHandle;        // Get the property type.
    return(AECreateDesc(propType, (Ptr)&window, sizeof(Ptr), resultToken)); 
}
 
//----------------------------------------------------------------------------------//
//  Return a token that contains the property type and nil to represent the null    //
//  container (the application).                                                    //
//----------------------------------------------------------------------------------//
#pragma segment Main
pascal
OSErr AppPropertyAccessor(  DescType        classWanted,            // Property class.
                            AEDesc*         container,              // Application.
                            DescType        containerClass, 
                            DescType        form,
                            AEDesc*         selectionData,
                            AEDesc*         resultToken,
                            long            theRefCon   )
{   
    #pragma unused (container,containerClass,theRefCon)
    DescType        propType;
    long            nilValue;
    
            //  Let's make sure we're accessing a valid descriptor type.
    if ((classWanted != cProperty) || (form != formPropertyID))
        return(errAEWrongDataType);
    nilValue = nil;     
    propType = *(LongPtr)*selectionData->dataHandle;            // Get the property type.
    return(AECreateDesc(propType, (Ptr)&nilValue, sizeof(long), resultToken)); 
}
 
//----------------------------------------------------------------------------------//
//  Returns the window with the given title if found.  Otherwise, nil is returned.  //
//  Use WindowList in order to find windows that may be invisible.                  //
//----------------------------------------------------------------------------------//
#pragma segment Main
WindowPtr GetWindowWithTitle( ConstStr255Param  titleToFind )
{
    WindowPeek  window;
    Str255      thisTitle;
    
#ifdef  THINK_C
    window = (WindowPeek)LMGetWindowList(); // WindowList finds invisible windows as well.
#else
    window = *(PeekPtr)LMGetWindowList();       // WindowList finds invisible windows as well.
#endif
    
    while (window)
    {
        GetWTitle((WindowPtr)window, thisTitle);
        if (EqualString(thisTitle, titleToFind, false, false))
            return((WindowPtr)window);
        window = window->nextWindow;
    }
    return(nil);
}
 
//----------------------------------------------------------------------------------//
//  Search all windows (including invisible), and return the window at the given    //
//  index if found. Otherwise, nil is returned. This routine also handles negative  //
//  indices which indicates that the offset is from the end of the container.       //                                  //
//----------------------------------------------------------------------------------//
#pragma segment Main
WindowPtr GetWindowAtIndex(long  index)
{
    WindowPeek  window;
    short       count;
    
    index = index < 0 ? gNumWindowsOpen+index+1 : index;
    count = 1;
    
#ifdef  THINK_C
    window = (WindowPeek)LMGetWindowList(); // WindowList finds invisible windows as well.
#else
    window = *(PeekPtr)LMGetWindowList();       // WindowList finds invisible windows as well.
#endif
 
    while (window)
    {
        if (count == index)
            return((WindowPtr)window);
        window = window->nextWindow;
        count++;
    }
    return(nil);
}
 
//----------------------------------------------------------------------------------//
//  Returns the index number of the given window, where 1 is the frontmost.         //
//----------------------------------------------------------------------------------//
#pragma segment Main
long GetWindowIndexNum(WindowPtr myWindow)
{
    WindowPeek  thisWindow;
    long        index;
    
#ifdef  THINK_C
    thisWindow = (WindowPeek)LMGetWindowList();     // Compilers are so much fun!!.
#else
    thisWindow = *(PeekPtr)LMGetWindowList();           // WindowList finds invisible windows as well.
#endif
 
    index = 1;
    
    while (thisWindow)
    {
        if (thisWindow == (WindowPeek)myWindow)     // [pwpc]
            return(index);
        thisWindow = thisWindow->nextWindow;
        index++;
    }
    return(nil);
}
 
//----------------------------------------------------------------------------------//
//  This routine returns the bounds of a given window. Special calculations are     //
//  performed when the bounds is invalid (i.e., the window is hidden).              //
//----------------------------------------------------------------------------------//
#pragma segment Main
Rect DoGetWindowBounds(WindowPtr window)
{
    Rect    portRect, bitMapRect, bounds;
    
    bounds = (*((WindowPeek)window)->contRgn)->rgnBBox;     // check the content region.
    if (bounds.top == 0 && bounds.left == 0 &&
        bounds.bottom == 0 && bounds.right == 0)
    {
        portRect = window->portRect;
        bitMapRect = window->portBits.bounds;
        
        bounds.top =  portRect.top - bitMapRect.top;
        bounds.left = portRect.left - bitMapRect.left;
        bounds.bottom = portRect.bottom - bitMapRect.top;
        bounds.right = portRect.right - bitMapRect.left;
    }
    return(bounds);
}
 
//----------------------------------------------------------------------------------//
#pragma segment Initialize
void InitAEHandlers()
{
    AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,NewAEEventHandlerProc(HandleOpenApp), nil,false);
    AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,NewAEEventHandlerProc(DummyHandler), nil,false);
    AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,NewAEEventHandlerProc(DummyHandler), nil,false);
    AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerProc(HandleQuitApp), nil, false);
    AEInstallEventHandler(kAECoreSuite, kAEClone, NewAEEventHandlerProc(HandleClone), nil, false);
    AEInstallEventHandler(kAECoreSuite, kAEClose, NewAEEventHandlerProc(HandleClose), nil, false);
    AEInstallEventHandler(kAECoreSuite, kAECountElements, NewAEEventHandlerProc(HandleCountElements), nil, false);
    AEInstallEventHandler(kAECoreSuite, kAECreateElement, NewAEEventHandlerProc(HandleCreateElement), nil, false);
    AEInstallEventHandler(kAECoreSuite, kAEDelete, NewAEEventHandlerProc(HandleClose), nil, false);
    AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist, NewAEEventHandlerProc(HandleDoObjectsExist), nil, false);
    AEInstallEventHandler(kAECoreSuite, kAEGetData, NewAEEventHandlerProc(HandleGetData), kAEGetData, false);
    AEInstallEventHandler(kAECoreSuite, kAEGetDataSize, NewAEEventHandlerProc(HandleGetData), kAEGetDataSize, false);
    AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo, NewAEEventHandlerProc(DummyHandler), nil, false);
    AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo, NewAEEventHandlerProc(DummyHandler), nil, false);
    AEInstallEventHandler(kAECoreSuite, kAEMove, NewAEEventHandlerProc(HandleMove), nil, false);
    AEInstallEventHandler(kAECoreSuite, kAESave, NewAEEventHandlerProc(DummyHandler), nil, false);
    AEInstallEventHandler(kAECoreSuite, kAESetData, NewAEEventHandlerProc(HandleSetData), nil, false);
 
    AEObjectInit();
    AEInstallObjectAccessor(cWindow, typeNull, NewOSLAccessorProc(WindowAccessor), nil, false);
    AEInstallObjectAccessor(cProperty, typeNull, NewOSLAccessorProc(AppPropertyAccessor), nil, false);
    AEInstallObjectAccessor(cProperty, cWindow, NewOSLAccessorProc(WindowPropertyAccessor), nil, false);
}