Source/SVAERecording.c

/*
    File:       SVAERecording.c
 
    Contains:   
 
    Written by: Original version by Jon Lansdell and Nigel Humphreys.
                3.1 updates by Greg Sutton.
 
    Copyright:  Copyright © 1995-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/20/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
 
#include "SVAERecording.h"
 
#include "SVEditAEUtils.h"
#include "SVEditUtils.h"
#include "SVAEWindowUtils.h"
#include "SVAETextUtils.h"
#include "SVAppleEvents.h"
 
#include <AEPackObject.h>
#include <TextUtils.h>
 
 
 
static short   gBigBrother;
static char    *gTypingBuffer;
static short   gCharsInBuffer;
static AEDesc  gTypingTargetObject;
 
OSErr   InstallRecordingHandlers(void)
{
    OSErr   err;
    
    gBigBrother = 0;
    gCharsInBuffer = 0;
    gTypingBuffer = (char *)NewPtr(32000);
    gTypingTargetObject.dataHandle = 0;
    
    err = AEInstallEventHandler( kCoreEventClass, kAENotifyStartRecording, NewAEEventHandlerProc(HandleStartRecording), noRefCon, false);
    err = AEInstallEventHandler( kCoreEventClass, kAENotifyStopRecording, NewAEEventHandlerProc(HandleStopRecording), noRefCon, false);
 
    return(err);
}
 
pascal OSErr HandleStartRecording(const AppleEvent *theAppleEvent,
                                                          AppleEvent *reply,
                                                          long       handlerRefCon)     
{
#pragma unused (reply,handlerRefCon)
 
    OSErr myErr;
 
    gBigBrother++;
 
    myErr = GotRequiredParams(theAppleEvent);
 
    return(myErr);
    
} // HandleStartRecording
 
pascal OSErr HandleStopRecording(const AppleEvent *theAppleEvent,
                                                         AppleEvent *reply,
                                                             long handlerRefCon)        
{
#pragma unused (theAppleEvent,reply,handlerRefCon)
 
    gBigBrother--;
    return(noErr);
} // HandleStopRecording
 
 
// Make an object specifier for a window given the WindowPtr
 
OSErr   MakeWindowObj(WindowPtr theWindow, AEDesc *result)
{
    AEDesc  nullDesc = {typeNull, NULL},
            absoluteDesc = {typeNull, NULL};
    long    windowIndex;
    OSErr   err;
    
    windowIndex = GetNthWindowOfWindowPtr(theWindow);
    if (! windowIndex)
        return(errAENoSuchObject);
    
    err = AECreateDesc(typeInteger,(Ptr)&windowIndex, sizeof(windowIndex), &absoluteDesc);
    if (noErr != err) goto done;
    
    err = CreateObjSpecifier(cWindow, &nullDesc, formAbsolutePosition,
                                                &absoluteDesc, false, result);
 
done:
    if (absoluteDesc.dataHandle)
        AEDisposeDesc(&absoluteDesc);
    
    return(err);
} // MakeWindowObj
 
// Make an object specifier for a document given the WindowPtr
 
OSErr   MakeDocumentObj(WindowPtr theWindow, AEDesc *result)
{
    AEDesc  nullDesc = {typeNull, NULL},
            absoluteDesc = {typeNull, NULL};
    long    windowIndex;
    OSErr   err;
    
    windowIndex = GetNthWindowOfWindowPtr(theWindow);
    if (! windowIndex)
        return(errAENoSuchObject);
    
    err = AECreateDesc(typeInteger,(Ptr)&windowIndex, sizeof(windowIndex), &absoluteDesc);
    if (noErr != err) goto done;
    
    err = CreateObjSpecifier(cDocument, &nullDesc, formAbsolutePosition,
                                                &absoluteDesc, false, result);
 
done:
    if (absoluteDesc.dataHandle)
        AEDisposeDesc(&absoluteDesc);
    
    return(err);
} // MakeDocumentObj
 
 
OSErr   MakeTextObjFromToken(TextToken* theToken, AEDesc* result)
{
    OSErr   err;
 
    err = GetTextTokenObjectSpecifier(theToken, result);
    
    return(err);
}
 
 
OSErr   MakeSelectedTextObj(WindowPtr theWindow, TEHandle theTextEditHandle, AEDesc* result)
{
    return( MakeTextObj(theWindow, (**theTextEditHandle).selStart,
                            (**theTextEditHandle).selEnd, result));
} // MakeSelectedTextObj
 
 
OSErr   MakeTextObj(WindowPtr theWindow, short selStart, short selEnd, AEDesc* result)
{
    TextToken   aToken;
    OSErr       err;
    
    aToken.tokenWindow = theWindow;
    aToken.tokenOffset = selStart + 1;
    aToken.tokenLength = selEnd - selStart;
 
    err = MakeTextObjFromToken(&aToken, result);
 
    return(err);
}
 
OSErr   SendSelectionEvent(DPtr docPtr)
{
    AEAddressDesc   ourAddress = {typeNull, NULL};
    AppleEvent      selectEvent = {typeNull, NULL},
                    ignoreReply = {typeNull, NULL};
    AEDesc          textObj = {typeNull, NULL};
    OSErr           err;
 
 
    err = MakeSelfAddress(&ourAddress);
    if (noErr != err) goto done;
    
        // Build an object to represent the current document's selection
        // MakeSelectedTextObj
    err = MakeSelectedTextObj(docPtr->theWindow, docPtr->theText, &textObj);
    if (noErr != err) goto done;
    
    err = AECreateAppleEvent(kAEMiscStandards, kAESelect, &ourAddress, 0, 0, &selectEvent); 
    if (noErr != err) goto done;
    
        // add parameter
    err = AEPutParamDesc(&selectEvent, keyDirectObject, &textObj);
    if (noErr != err) goto done;
                    
        // and now send the message
    err = AESend(&selectEvent, &ignoreReply, kAENoReply, kAEHighPriority, kAEDefaultTimeout, NULL, NULL);
    if (noErr != err) goto done;
 
done:   
    if (ourAddress.dataHandle) 
        AEDisposeDesc(&ourAddress);
    if (selectEvent.dataHandle) 
        AEDisposeDesc(&selectEvent);
    if (ignoreReply.dataHandle) 
        AEDisposeDesc(&ignoreReply);
    if (textObj.dataHandle) 
        AEDisposeDesc(&textObj);
 
    return(err);
}
 
void    DoEditCommand(DPtr theDocument, editCommandType whatCommand)
{
    AEAddressDesc   ourAddress = {typeNull, NULL};
    AppleEvent      editCommandEvent = {typeNull, NULL},
                    ignoreReply = {typeNull, NULL};
    AEEventID       theEventID;
    AEEventClass    theEventClass;
    OSErr           err;
    
    err = SendSelectionEvent(theDocument);
    if (noErr != err) goto done;
 
        // Now create and send the appropriate cut, copy, paste or clear AppleEvent
    
    switch (whatCommand)
    {
        case  editCutCommand:
            theEventID = kAECut;
            theEventClass = kAEMiscStandards;
            break;
            
        case  editCopyCommand:
            theEventID = kAECopy;
            theEventClass = kAEMiscStandards;
            break;
 
        case  editPasteCommand:
            theEventID = kAEPaste;
            theEventClass = kAEMiscStandards;
            break;
 
        case  editClearCommand:
            theEventID = kAEDelete;
            theEventClass = kAECoreSuite;
            break;
    }
    
    err = MakeSelfAddress(&ourAddress);
    if (noErr != err) goto done;
            
    err = AECreateAppleEvent(theEventClass, theEventID, &ourAddress, 0, 0, &editCommandEvent);  
    if (noErr != err) goto done;
            
        // and now Send the message
    err = AESend(&editCommandEvent, &ignoreReply, kAENoReply, kAEHighPriority, kAEDefaultTimeout, NULL, NULL);
        
done:
    if (ourAddress.dataHandle) 
        AEDisposeDesc(&ourAddress);
    if (editCommandEvent.dataHandle) 
        AEDisposeDesc(&editCommandEvent);
    if (ignoreReply.dataHandle) 
        AEDisposeDesc(&ignoreReply);
 
} // DoEditCommand
 
void    IssueCutCommand(DPtr theDocument)
{           
    DoEditCommand(theDocument, editCutCommand);
} 
 
void    IssueCopyCommand(DPtr theDocument)
{
    DoEditCommand(theDocument, editCopyCommand);
}
 
void    IssuePasteCommand(DPtr theDocument)
{
    DoEditCommand(theDocument, editPasteCommand);   
}
 
void    IssueClearCommand(DPtr theDocument)
{
    DoEditCommand(theDocument, editClearCommand);   
}
 
// ---------------------------------------------------------------------
//  Name :      SendAESetObjProp
//  Function :  Creates a property object from an object,
//              a property type and its data and sends it to
//              the requested address, and cleans up zapping params too
// ---------------------------------------------------------------------
 
OSErr   SendAESetObjProp(AEDesc *theObj, DescType theProp, AEDesc *theData, AEAddressDesc *toWhom)
{
    AEDesc      propObjSpec;
    AppleEvent  myAppleEvent;
    AppleEvent  defReply;
    OSErr       myErr;
    OSErr       ignoreErr;
    AEDesc      theProperty;
        
    // create an object spec that represents the property of the given object
    
    myErr = AECreateDesc(typeType, (Ptr)&theProp, sizeof(theProp), &theProperty);
    if (myErr==noErr)
        myErr = CreateObjSpecifier(cProperty, theObj, formPropertyID,
                                        &theProperty, true, &propObjSpec);  
        
    // create event
    
    if (myErr==noErr)
        myErr = AECreateAppleEvent(kAECoreSuite, kAESetData, toWhom, 0, 0, &myAppleEvent);
        
    // add prop obj spec to the event
    
    if (myErr==noErr)
        myErr = AEPutParamDesc(&myAppleEvent, keyDirectObject, &propObjSpec);
    
    // add prop data to the event
    
    if (myErr==noErr)
        myErr = AEPutParamDesc(&myAppleEvent,keyAEData, theData);
    
    // send event
    
    if (myErr==noErr)
        myErr = AESend(&myAppleEvent, &defReply, kAENoReply+kAEAlwaysInteract,
                                    kAENormalPriority, kAEDefaultTimeout, nil, nil);
    
    if (myAppleEvent.dataHandle)
        ignoreErr = AEDisposeDesc(&myAppleEvent);
        
    if (&propObjSpec.dataHandle)
      ignoreErr = AEDisposeDesc(&propObjSpec);
    
    if (theData->dataHandle)
        ignoreErr = AEDisposeDesc(theData);
    
    if (toWhom->dataHandle)
        ignoreErr = AEDisposeDesc(toWhom);
    
    return(myErr);
} // SendAESetObjProp
 
 
void    IssueFontCommand(DPtr theDocument, short theItem)
{
    Str255          name;
    AEDesc          strDesc;
    AEAddressDesc   theAddress;
    AEDesc          selTextObj;
    OSErr           err;
        
    err = MakeSelfAddress(&theAddress);
    
    err = MakeSelectedTextObj(theDocument->theWindow, theDocument->theText, &selTextObj);
    
    GetMenuItemText(myMenus[fontM], theItem, name);
    
    if (err==noErr)
        err  = AECreateDesc(typeChar, (Ptr)&name[1], name[0], &strDesc);
    
    if (err==noErr)
        err  = SendAESetObjProp(&selTextObj, pFont, &strDesc, &theAddress);                                                         
}
 
// Window property routines
 
void    IssueZoomCommand(WindowPtr whichWindow, short whichPart)
{
    Boolean       zoomBool;
    AEDesc        zoomDesc;
    AEAddressDesc selfAddr;
    AEDesc        frontWinObj;
    OSErr         err;
 
    err = MakeSelfAddress(&selfAddr);
    
    err = MakeWindowObj(whichWindow, &frontWinObj);
    
    zoomBool = (whichPart==inZoomOut);
 
    err = AECreateDesc(typeBoolean, (Ptr)&zoomBool, sizeof(zoomBool), &zoomDesc);
                                            
    err = SendAESetObjProp(&frontWinObj, pIsZoomed, &zoomDesc, &selfAddr);                                                          
} // IssueZoomCommand
 
void    IssueCloseCommand(WindowPtr whichWindow)
{
    AEAddressDesc  selfAddr;
    AEDesc         frontWinObj;
    OSErr          err;
    OSErr          ignoreErr;
    AppleEvent     closeCommandEvent;
    AppleEvent     ignoreReply;
 
    frontWinObj.dataHandle = nil;
    
    err = MakeSelfAddress(&selfAddr);
    
    err = MakeWindowObj(whichWindow, &frontWinObj);
                                                        
    err = AECreateAppleEvent( kAECoreSuite, kAEClose, &selfAddr, 0, 0, &closeCommandEvent) ;                
    
    // add parameter - the window to close  
    if (err==noErr) 
        err = AEPutParamDesc(&closeCommandEvent, keyDirectObject, &frontWinObj);
        
    if (err==noErr) 
        err = AESend(&closeCommandEvent,&ignoreReply,kAENoReply+kAEAlwaysInteract,kAEHighPriority,10000,nil, nil);
    
    if (closeCommandEvent.dataHandle) 
        ignoreErr = AEDisposeDesc(&closeCommandEvent);
    
    if (selfAddr.dataHandle) 
        ignoreErr = AEDisposeDesc(&selfAddr);
        
    if (frontWinObj.dataHandle) 
        ignoreErr = AEDisposeDesc(&frontWinObj);
        
} // IssueCloseCommand
 
void    IssueSizeWindow(WindowPtr whichWindow, short newHSize, short newVSize)
{
    Rect          sizeRect;
    Rect          contentRect;
    short         edgeSize;
    AEDesc        sizeDesc;
    AEAddressDesc selfAddr;
    AEDesc        frontWinObj;
    OSErr         err;
 
    sizeRect    = (**(((WindowPeek)whichWindow)->strucRgn)).rgnBBox;
    contentRect = (**(((WindowPeek)whichWindow)->contRgn)).rgnBBox;
    
    edgeSize = sizeRect.right-sizeRect.left-(contentRect.right-contentRect.left);
    sizeRect.right = sizeRect.left+newHSize+edgeSize;
    
    edgeSize = sizeRect.bottom-sizeRect.top-(contentRect.bottom-contentRect.top);
    sizeRect.bottom = sizeRect.top+newVSize+edgeSize;
    
    err = MakeSelfAddress(&selfAddr);
    
    err = MakeWindowObj(whichWindow, &frontWinObj);
    
    if (err==noErr)
        err = AECreateDesc(typeQDRectangle, (Ptr)&sizeRect, sizeof(sizeRect), &sizeDesc);
    
    if (err==noErr)
        err  = SendAESetObjProp(&frontWinObj, pBounds, &sizeDesc, &selfAddr);                                                           
} // IssueSizeWindow
 
void    IssueMoveWindow(WindowPtr whichWindow, Rect sizeRect)
{
    AEDesc        sizeDesc;
    AEAddressDesc selfAddr;
    AEDesc        frontWinObj;
    OSErr         err;
 
    err = MakeSelfAddress(&selfAddr);
    
    err = MakeWindowObj(whichWindow, &frontWinObj);
        
    if (err==noErr)
        err = AECreateDesc(typeQDRectangle, (Ptr)&sizeRect, sizeof(sizeRect), &sizeDesc);
    
    if (err==noErr)     
        err = SendAESetObjProp(&frontWinObj, pBounds, &sizeDesc, &selfAddr);                                                            
} // IssueMoveWindow
 
void    IssuePageSetupWindow(WindowPtr whichWindow, TPrint thePageSetup)
{
    AEDesc        sizeDesc;
    AEAddressDesc selfAddr;
    AEDesc        frontWinObj;
    OSErr         err;
 
    err = MakeSelfAddress(&selfAddr);
    
    err = MakeWindowObj(whichWindow, &frontWinObj);
    
    if (err==noErr)
        err = AECreateDesc(typeTPrint, (Ptr)&thePageSetup, sizeof(thePageSetup), &sizeDesc);
                                             
    if (err==noErr)
        err = SendAESetObjProp(&frontWinObj, pPageSetup, &sizeDesc, &selfAddr);                                                         
                                                 
} //IssuePageSetupWindow
 
 
void IssuePrintWindow(WindowPtr whichWindow, Boolean useDialog)
{
    AEAddressDesc selfAddr;
    AEDesc        frontWinObj;
    OSErr         err;
    OSErr         ignoreErr;
    AppleEvent    printCommandEvent;
    AppleEvent    ignoreReply;
    AESendMode    sendModeFlags;
 
    err = MakeSelfAddress(&selfAddr);
    
    err = MakeWindowObj(whichWindow, &frontWinObj);
                                                        
    err = AECreateAppleEvent(kCoreEventClass, kAEPrintDocuments, &selfAddr, 0, 0, &printCommandEvent) ;             
 
    //  add parameter - the window to print
 
    if (err==noErr) 
        err = AEPutParamDesc(&printCommandEvent, keyDirectObject, &frontWinObj);
        
    if (err==noErr)
    {
        sendModeFlags = kAENoReply;
        if (useDialog)
            sendModeFlags = sendModeFlags + kAEAlwaysInteract;
        else
            sendModeFlags = sendModeFlags + kAENeverInteract;
        err = AESend(&printCommandEvent,&ignoreReply,sendModeFlags,kAEHighPriority,10000,nil, nil);
    }
    
    if (printCommandEvent.dataHandle)
        ignoreErr = AEDisposeDesc(&printCommandEvent);
    
    if (frontWinObj.dataHandle) 
        err = AEDisposeDesc(&frontWinObj);
        
    if (selfAddr.dataHandle) 
        err = AEDisposeDesc(&selfAddr);
        
} // IssuePrintWindow
 
OSErr   IssueAEOpenDoc(FSSpec myFSSpec)
// send OpenDocs AppleEvent to myself, with a one-element list
// containing the given file spec
//
// NOTES : the core AEOpenDocs event is defined as taking a list of
//      aliases (not file specs) as its direct parameter.  However,
//      we can send the file spec instead and depend on AppleEvents'
//      automatic coercion.  In fact, we don't really even have to put 
//      in a list; AppleEvents will coerce a descriptor into a 1-element
//      list if called for.  In this routine, though, we'll make the
//      list for demonstration purposes.
{
    AppleEvent    myAppleEvent;
    AppleEvent    defReply;
    AEDescList    docList;
    AEAddressDesc selfAddr;
    OSErr         myErr;
    OSErr         ignoreErr;
    
    myAppleEvent.dataHandle = nil;
    docList.dataHandle  = nil;
    selfAddr.dataHandle = nil;
    defReply.dataHandle = nil;
        
    //  Create empty list and add one file spec
 
    myErr = AECreateList(nil,0,false, &docList);
    
    if (myErr==noErr) 
        myErr = AEPutPtr(&docList,1,typeFSS,(Ptr)&myFSSpec,sizeof(myFSSpec));
        
    //  Create a self address to send it to
 
    if (myErr==noErr) 
        myErr = MakeSelfAddress(&selfAddr);
        
    if (myErr==noErr) 
        myErr = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &selfAddr,
                                kAutoGenerateReturnID,  kAnyTransactionID, &myAppleEvent);
 
    //  Put Params into our event and send it
 
    if (myErr == noErr) 
        myErr = AEPutParamDesc(&myAppleEvent, keyDirectObject, &docList);
 
    myErr = AESend(&myAppleEvent, &defReply, kAENoReply+kAEAlwaysInteract, kAENormalPriority,
                                                                    kAEDefaultTimeout, nil, nil);
        
    if (selfAddr.dataHandle) 
        ignoreErr = AEDisposeDesc(&selfAddr);
        
    if (myAppleEvent.dataHandle) 
        ignoreErr = AEDisposeDesc(&myAppleEvent);
        
    if (docList.dataHandle) 
        ignoreErr = AEDisposeDesc(&docList);
        
    return(myErr);
    
} // IssueAEOpenDoc
 
void    IssueAENewWindow(void)
// send the New Element event to myself with a null container
{
    AppleEvent    myAppleEvent;
    AppleEvent    defReply;
    AEAddressDesc selfAddr;
    OSErr         myErr;
    OSErr         ignoreErr;
    DescType      elemClass;
    
    myAppleEvent.dataHandle = nil;
    
    //  Create the address of us
    
    myErr = MakeSelfAddress(&selfAddr);
    
    //  create event 
    
    myErr = AECreateAppleEvent(kAECoreSuite, kAECreateElement, &selfAddr,
                                    kAutoGenerateReturnID, kAnyTransactionID, &myAppleEvent);
    
    //  attach desired class of new element
    
    elemClass = cWindow;
    
    if (myErr == noErr) 
        myErr = AEPutParamPtr(&myAppleEvent, keyAEObjectClass, typeType,
                                        (Ptr)&elemClass, sizeof(elemClass));
        
    //  send the event 
    
    if (myErr == noErr) 
        myErr = AESend(&myAppleEvent, &defReply, kAENoReply+kAENeverInteract,
                            kAENormalPriority, kAEDefaultTimeout, nil, nil);
    //  Clean up - reply never created so don't throw away
 
    if (selfAddr.dataHandle) 
        ignoreErr = AEDisposeDesc(&selfAddr);
        
    if (myAppleEvent.dataHandle) 
        ignoreErr = AEDisposeDesc(&myAppleEvent);
                
} // IssueAENewWindow
 
OSErr   IssueSaveCommand(WindowPtr theWindow, FSSpecPtr where)
// send an AppleEvent Save Event to myself
{
    AEDesc        windowObj;
    AppleEvent    myAppleEvent;
    AppleEvent    defReply;
    OSErr         myErr;
    OSErr         ignoreErr;
    AEAddressDesc selfAddr;
        
    windowObj.dataHandle = nil;
    myAppleEvent.dataHandle = nil;
    
    myErr = MakeWindowObj(theWindow, &windowObj);
          
    if (myErr==noErr) 
        myErr = MakeSelfAddress(&selfAddr);
    
        //  Build event
 
    if (myErr == noErr) 
        myErr = AECreateAppleEvent(kAECoreSuite, kAESave, &selfAddr,
                            kAutoGenerateReturnID, kAnyTransactionID, &myAppleEvent);
  
        //  say which window
 
    if (myErr==noErr) 
        myErr = AEPutParamDesc(&myAppleEvent, keyDirectObject, &windowObj);
 
        //  add optional file param if we need to
 
    if (where) 
        if (myErr==noErr) 
            myErr = AEPutParamPtr(&myAppleEvent, keyAEDestination, typeFSS,
                                                    (Ptr)where, sizeof(FSSpec));
    
        // send the event
 
    if (myErr==noErr) 
        myErr  = AESend(&myAppleEvent, &defReply, kAENoReply+kAENeverInteract,
                                    kAENormalPriority, kAEDefaultTimeout, nil, nil);
      
    if (selfAddr.dataHandle) 
        ignoreErr = AEDisposeDesc(&selfAddr);
      
    if (windowObj.dataHandle) 
        ignoreErr = AEDisposeDesc(&windowObj);
        
    if (myAppleEvent.dataHandle) 
        myErr = AEDisposeDesc(&myAppleEvent);
        
    return(myErr);
}   // IssueSaveCommand
 
OSErr   IssueRevertCommand(WindowPtr theWindow)
    // send an AppleEvent Revert Event to myself
{
    AEDesc        windowObj;
    AppleEvent    myAppleEvent;
    AppleEvent    defReply;
    OSErr         myErr;
    OSErr         ignoreErr;
    AEAddressDesc selfAddr;
    
    windowObj.dataHandle = nil;
    myAppleEvent.dataHandle = nil;
    
    myErr = MakeWindowObj(theWindow, &windowObj);
                
    if (myErr==noErr) 
        myErr = MakeSelfAddress(&selfAddr);
        
    // Build event
    
    if (myErr == noErr) 
        myErr  = AECreateAppleEvent(kAEMiscStandards, kAERevert, &selfAddr,
                                    kAutoGenerateReturnID, kAnyTransactionID, &myAppleEvent);
    // say which window
    
    if (myErr == noErr) 
        myErr = AEPutParamDesc(&myAppleEvent, keyDirectObject, &windowObj);
    //  send the event
 
    if (myErr==noErr) 
        myErr  = AESend(&myAppleEvent, &defReply, kAENoReply+kAENeverInteract,
                                kAENormalPriority, kAEDefaultTimeout, nil, nil);
        
    if (windowObj.dataHandle) 
        ignoreErr = AEDisposeDesc(&windowObj);
        
    if (myAppleEvent.dataHandle) 
        ignoreErr = AEDisposeDesc(&myAppleEvent);
        
    if (selfAddr.dataHandle) 
        ignoreErr = AEDisposeDesc(&selfAddr);
        
    return(myErr);
} // IssueRevertCommand
 
// ----------------------------------------------------
//  Name :      IssueQuitCommand
//  Purpose :   Sends self a Quit AppleEvent
// ----------------------------------------------------
OSErr   IssueQuitCommand(void)
{
    AppleEvent    myAppleEvent;
    AppleEvent    defReply;
    OSErr         myErr;
    OSErr         ignoreErr;
    AEAddressDesc selfAddr;
    DescType      mySaveOpt;
    
    myAppleEvent.dataHandle = nil;
    selfAddr.dataHandle     = nil;
                        
    myErr = MakeSelfAddress(&selfAddr);
        
    //  Build event
    
    if (myErr == noErr) 
        myErr  = AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, &selfAddr,
                                        kAutoGenerateReturnID, kAnyTransactionID, &myAppleEvent);
    //  say which save option
    
    mySaveOpt = kAEAsk;
    
    if (myErr == noErr) 
        myErr = AEPutParamPtr(&myAppleEvent, keyAESaveOptions, typeEnumerated,
                                                (Ptr)&mySaveOpt, sizeof(mySaveOpt));
    //  send the event
 
    if (myErr==noErr) 
        myErr  = AESend(&myAppleEvent, &defReply, kAENoReply+kAEAlwaysInteract,
                                    kAENormalPriority, kAEDefaultTimeout, nil, nil);
                    
    if (myAppleEvent.dataHandle) 
        ignoreErr = AEDisposeDesc(&myAppleEvent);
        
    if (selfAddr.dataHandle) 
        ignoreErr = AEDisposeDesc(&selfAddr);
        
    return(myErr);
} // IssueQuitCommand
 
#define kOK 1
#define kCancel 2
#define kOtherSize 4
#define kOutlineItem 5
 
Boolean PoseSizeDialog(long *whatSize)
{
    GrafPtr   savedPort;
    DialogPtr aDialog;
    Str255    aString;
    short     itemHit;
 
    GetPort(&savedPort);
    aDialog = GetNewDialog(1004, nil, (WindowPtr)-1);
    ShowWindow(aDialog);
    SetPort(aDialog);
    
    AdornDefaultButton(aDialog, kOutlineItem);
     
        //set the edittext button to contain the right size
    NumToString(*whatSize, aString);
    SetText(aDialog, kOtherSize, aString);
 
    do
    {
        ModalDialog(nil, &itemHit);
    } while ((itemHit!=kOK) && (itemHit!=kCancel));
    
    if (itemHit == kOK) 
        RetrieveText(aDialog, kOtherSize, aString);
 
    DisposeDialog(aDialog);
    SetPort(savedPort);
    
    if (itemHit == kOK) 
    {
        // set the new size of the text
        StringToNum(aString, whatSize);
        if ((*whatSize<1) || (*whatSize>2000)) 
            *whatSize = 12;
    }
 
    return(itemHit == kOK);
}
 
void    IssueSizeCommand(DPtr theDocument,short theItem)
{
    Str255        name;
    AEDesc        sizeDesc;
    AEAddressDesc theAddress;
    OSErr         err;
    AEDesc        selTextObj;
    
        // Vars to do with menu processing
    short     lastSize;
    short     upItem;
    short     downItem;
    short     otherItem;
    long      theSize;
    TextStyle theStyle;
    short     lineHeight;
    short     fontAscent;
        
    err = MakeSelfAddress(&theAddress);
    
    err = MakeSelectedTextObj(theDocument->theWindow, theDocument->theText, &selTextObj);       
 
        // check if the item is on the Size menu
        // remembering that we can add and delete items from it
    lastSize  = CountMItems(myMenus[sizeM]) - 5;
    upItem    = lastSize + 2;
    downItem  = upItem + 1;
    otherItem = downItem + 2;
  
    TEGetStyle((**(theDocument->theText)).selStart, &theStyle, &lineHeight,
                                            &fontAscent, theDocument->theText);
    
    GetMenuItemText(myMenus[sizeM], theItem, name);
 
    if (theItem <= lastSize)
    {
        GetMenuItemText(myMenus[sizeM], theItem, name);
        StringToNum(name, &theSize);
    }
    else if (theItem == upItem)  
        theSize = theStyle.tsSize + 1;
    else if (theItem == downItem)
        theSize = theStyle.tsSize - 1;
    else if (theItem == otherItem) 
    {
        theSize = theStyle.tsSize;
        if (!PoseSizeDialog(&theSize))
            return;
    }
 
    if (err==noErr)
        err = CreateOffsetDescriptor(theSize, &sizeDesc);
    
    if (err==noErr)
        err = SendAESetObjProp(&selTextObj, pPointSize, &sizeDesc, &theAddress);
} // IssueSizeCommand
 
void    IssueStyleCommand(DPtr theDocument, short theItem)
{
    Style         theFace;
    OSErr         err;
    AEDesc        result;
    AEAddressDesc selfAddr;
    AEDesc        selTextObj;
    TextStyle     theStyle;
    short         lineHeight;
    short         fontAscent;
        
    TEGetStyle((**(theDocument->theText)).selStart, &theStyle,
                    &lineHeight, &fontAscent, theDocument->theText);
    
    theFace = 0;
 
    switch (theItem)
    {
        case cPlain:
            theFace = 0;
            break;
        case cBold:
            theFace = bold;
            break;
        case cItalic:
            theFace = italic;
            break;
        case cUnderline:
            theFace = underline;
            break;
        case cOutline:
            theFace = outline;
            break;
        case cShadow:
            theFace = shadow;
            break;
        case cCondense:
            theFace = condense;
            break;
        case cExtend:
            theFace = extend;
            break;
    } // of switch
 
    if (theFace==0)
        err = BuildTypeTextStylesDesc(0, bold+italic+underline+outline+shadow+condense+extend, &result);
    else if (theFace & theStyle.tsFace)
        err = BuildTypeTextStylesDesc(0, theFace, &result);
    else
        err = BuildTypeTextStylesDesc(theFace, 0, &result);
    
    err = MakeSelfAddress(&selfAddr);
    
    if (err==noErr)
        err = MakeSelectedTextObj(theDocument->theWindow, theDocument->theText, &selTextObj);
    
    if (err==noErr)
        err = SendAESetObjProp(&selTextObj, pTextStyles, &result, &selfAddr);
} // IssueStyleCommand
 
 
OSErr   IssueSetDataObjToBufferContents(const AEDesc* theObj)
{ 
    OSErr           myErr;
    OSErr           ignoreErr;
    AEAddressDesc   theAddress;
    AppleEvent      myAppleEvent;
    AppleEvent      defReply;
 
    myErr = MakeSelfAddress(&theAddress);
    
    // create event
    
    if (myErr==noErr)
        myErr = AECreateAppleEvent(kAECoreSuite, kAESetData, &theAddress,
                                                        0, 0, &myAppleEvent);
        
    // add prop obj spec to the event
    
    if (myErr==noErr)
        myErr = AEPutParamDesc(&myAppleEvent, keyDirectObject, theObj);
    
    // add prop data to the event
    
    if (myErr==noErr)
        myErr = AEPutParamPtr(&myAppleEvent, keyAEData, typeChar,
                                    (Ptr)gTypingBuffer, gCharsInBuffer);
                                                    
    // send event
    
    if (myErr==noErr)
     if (gRecordingImplemented)
         myErr = AESend(&myAppleEvent, &defReply, kAENoReply+kAEDontExecute,
                                    kAENormalPriority, kAEDefaultTimeout, nil, nil);
 
    if (theAddress.dataHandle)
        ignoreErr = AEDisposeDesc(&theAddress);
        
    if (myAppleEvent.dataHandle)
        ignoreErr = AEDisposeDesc(&myAppleEvent);
        
    return(myErr);
}
 
void    AddKeyToTypingBuffer(DPtr theDocument, char theKey)
{
    OSErr myErr;
    OSErr ignoreErr;
    
    if (theKey==BS || theKey==FS || theKey==GS || theKey==RS || theKey==US)
    {
        FlushAndRecordTypingBuffer();
        if (theKey==BS)
        {
            if ((**theDocument->theText).selStart!=(**theDocument->theText).selEnd)
            {
                myErr = MakeTextObj(theDocument->theWindow,
                                    (**theDocument->theText).selStart,
                                    (**theDocument->theText).selEnd,
                                    &gTypingTargetObject);
            }
            else
            {
                myErr = MakeTextObj(theDocument->theWindow,
                                    (**theDocument->theText).selStart-1,
                                    (**theDocument->theText).selStart,
                                    &gTypingTargetObject);
            }
                
            myErr = IssueSetDataObjToBufferContents(&gTypingTargetObject);
            
            ignoreErr = AEDisposeDesc(&gTypingTargetObject);
            
            gTypingTargetObject.dataHandle = nil;
        }
    }
    else
    {
        if (gCharsInBuffer==0)
            myErr = MakeSelectedTextObj(theDocument->theWindow, theDocument->theText,
                                                                    &gTypingTargetObject);
 
        gTypingBuffer[gCharsInBuffer++] = theKey;
    }
}
 
void    FlushAndRecordTypingBuffer(void)
{ 
    OSErr  myErr;
    OSErr  ignoreErr;
 
    if (gCharsInBuffer != 0)
    {
        myErr = IssueSetDataObjToBufferContents(&gTypingTargetObject);
        
        if (gTypingTargetObject.dataHandle)
            ignoreErr = AEDisposeDesc(&gTypingTargetObject);
    }
        
    gCharsInBuffer = 0;
    gTypingTargetObject.dataHandle = 0;
}
 
    
void    StyleTokConst(short theStyleItem, DescType *thekConst)
{
    switch (theStyleItem)
    {
        case bold:
            *thekConst = kAEBold;
            break;
            
        case italic:
            *thekConst = kAEItalic;
            break;
            
        case underline:
            *thekConst = kAEUnderline;
            break;
            
        case outline:
            *thekConst = kAEOutline;
            break;
            
        case shadow:
            *thekConst = kAEShadow;
            break;
            
        case condense:
            *thekConst = kAECondensed;
            break;
            
        case extend:
            *thekConst = kAEExpanded;
            break;
    }
} // StyleTokConst
 
OSErr   BuildTypeTextStylesDesc(Style onStyles, Style offStyles, AEDesc *resultDesc)
{
 
    OSErr     myErr;
    OSErr     ignoreErr;
    short     myStyleItem;
    DescType  styleConst;
    AEDesc    onStylesDesc;
    AEDesc    offStylesDesc;
    AEDesc    dataDesc;
    
    onStylesDesc.dataHandle  = nil;
    offStylesDesc.dataHandle = nil;
    dataDesc.dataHandle  = nil;
 
    myErr = AECreateList(nil, 0, true,  &dataDesc);
    
    myErr = AECreateList(nil, 0, false, &onStylesDesc);
    myErr = AECreateList(nil, 0, false, &offStylesDesc);
    
    for (myStyleItem = bold; myStyleItem<=extend; myStyleItem = myStyleItem <<1)
        if (myErr==noErr)
        {
            StyleTokConst(myStyleItem, &styleConst);
            if (myStyleItem & onStyles)
                myErr = AEPutPtr(&onStylesDesc,
                                    0,              // add to end of list
                                    typeEnumerated, // text for style name
                                    (Ptr)&styleConst,
                                    sizeof(styleConst));
            
            if (myStyleItem & offStyles)
                myErr = AEPutPtr(&offStylesDesc,
                                    0,              // add to end of list
                                    typeEnumerated, // text for style name
                                    (Ptr)&styleConst,
                                    sizeof(styleConst));
        }
    
    if (myErr==noErr)
        myErr = AEPutKeyDesc(&dataDesc, keyAEOnStyles,  &onStylesDesc);
    
    if (myErr==noErr)
        myErr = AEPutKeyDesc(&dataDesc, keyAEOffStyles, &offStylesDesc);
    
    if (myErr==noErr)
        myErr = AECoerceDesc(&dataDesc, typeTextStyles, resultDesc);
        
    if (onStylesDesc.dataHandle)
        ignoreErr = AEDisposeDesc(&onStylesDesc);
        
    if (offStylesDesc.dataHandle)
        ignoreErr = AEDisposeDesc(&offStylesDesc);
        
    if (dataDesc.dataHandle)
        ignoreErr = AEDisposeDesc(&dataDesc);
 
    return(myErr);
}
 
OSErr   BuildTextStylesDesc(Style theStyle, AEDesc *resultDesc)
{
    short     myStyleItem;
    Style     onStyles;
    Style     offStyles;
            
    onStyles  = 0;
    offStyles = 0;
    
    for (myStyleItem = bold; myStyleItem<=extend; myStyleItem = myStyleItem <<1)
    {
        if (myStyleItem & theStyle)
            onStyles  = onStyles  + myStyleItem;
        else
            offStyles = offStyles + myStyleItem;
    }
 
    return(BuildTypeTextStylesDesc(onStyles, offStyles, resultDesc));
    
} // BuildTextStylesDesc
        
OSErr   BuildStyledTextDesc(TEHandle theHTE, short start, short howLong, AEDesc *resultDesc)
{
    AEDesc       listDesc;
    short        oldSelStart;
    short        oldSelEnd;
    StScrpHandle myStScrpHandle;
    OSErr        myErr;
    OSErr        ignoreErr;
    
    listDesc.dataHandle = nil;
    
    oldSelStart = (**theHTE).selStart;
    oldSelEnd   = (**theHTE).selEnd;
    
    TESetSelect(start-1, start+howLong-2, theHTE);
    
    myErr = AECreateList(nil, 0, true,  &listDesc);
    
    HLock((Handle)(**theHTE).hText);
                                                     
    if (myErr == noErr)
        myErr = AEPutKeyPtr(&listDesc, keyAEText, typeChar,
                            (Ptr)&(*(**theHTE).hText)[start-1], howLong);
                                                
    HUnlock((Handle)(**theHTE).hText);
    
    myStScrpHandle = TEGetStyleScrapHandle(theHTE);
    
    if (myStScrpHandle)
    {
        HLock((Handle)myStScrpHandle);
        
        if (myErr==noErr)
            myErr = AEPutKeyPtr(&listDesc, keyAEStyles, typeScrapStyles,
                                    (Ptr)*myStScrpHandle, GetHandleSize((Handle)myStScrpHandle));
            
        HUnlock((Handle)myStScrpHandle);
    }   
    else
        myErr = AEPutKeyPtr(&listDesc, keyAEStyles, typeScrapStyles, (Ptr)nil, 0);
    
    if (myErr==noErr)
        myErr = AECoerceDesc(&listDesc, typeStyledText, resultDesc); // should be typeIntlText
    
    if (listDesc.dataHandle)
        ignoreErr = AEDisposeDesc(&listDesc);
    
    TESetSelect(oldSelStart, oldSelEnd, theHTE);
    
    return(myErr);
}