Sources/MSAEGetData.c

// MSAEGetData.c
//
// Original version by Jon Lansdell and Nigel Humphreys.
// 4.0 and 3.1 updates by Greg Sutton.
// ©Apple Computer Inc 1996, all rights reserved.
 
/*
        Changes for 4.0
 
        29-Feb-96 : GS : Added abiltiy to get properties from menus and menu items.
        29-Feb-96 : GS : Added script properties to application and document objects.
*/
 
#include "MSAEGetData.h"
 
#include "MSWindow.h"
#include "MSGlobals.h"
#include "MSAEUtils.h"
#include "MSAppleEvents.h"
 
#include "MSAETextUtils.h"
#include "MSAEWindowUtils.h"
#include "MSAEMenuUtils.h"
#include "MSAccessors.h"
#include "MSAERecording.h"
#include "MSToken.h"
#include "MSScript.h"
#include "MSResultWind.h"
 
 
#include <AEPackObject.h>
#include <Resources.h>
#ifdef THINK_C
    #include "PLStrs.h"
#else
    #include <PLStringFuncs.h>
#endif
 
 
    // Globals
extern short        gRefNum;
 
// -----------------------------------------------------------------------
//      Name:           DoGetData
//      Purpose:        Handles the GetData AppleEvent.
// -----------------------------------------------------------------------
 
pascal OSErr     DoGetData(const AppleEvent *theAppleEvent,
                                AppleEvent  *reply,
                                long        handlerRefCon)
{ 
#ifdef __MWERKS__
    #pragma unused (handlerRefCon)
#endif
 
    AEDesc      directObj = {typeNull, NULL},
                result = {typeNull, NULL};
    Size        actualSize;
    DescType    returnedType;
    DescType    aWantType;
    OSErr       err;
    
        // extract the direct object, which is the object
        // whose data is to be returned
    err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeWildCard, &directObj);
    if (noErr != err) goto done;
        
        // now the get the type of data wanted - optional
    err = AEGetParamPtr( theAppleEvent, keyAERequestedType, typeType,
                                &returnedType, (Ptr)&aWantType, sizeof( aWantType ), &actualSize );
    if ( noErr != err )
        aWantType = typeWildCard;
        
    err = GotRequiredParams(theAppleEvent);
    if (noErr != err) goto done;
    
        // get the data
    err = HandleGetData( &directObj, aWantType, &result );
        
    err = AddResultToReply(&result, reply, err);
 
done:               
    (void)AEDisposeDesc( &directObj );
    (void)AEDisposeDesc( &result );
        
    return(err);
}   // DoGetData
 
 
// -----------------------------------------------------------------------
//  Name:       HandleGetData
//  Purpose:    Coerces theObj into a token which we understand and
//              extracts the data requested in the token and puts it
//              into dataDesc.
// -----------------------------------------------------------------------
 
OSErr   HandleGetData( AEDesc *theObj, DescType theWantType, AEDesc *result )
{
    TextToken       theTextToken;
    Size            tokenSize;
    AEDesc          objTokenDesc = {typeNull, NULL},
                    itemDesc = {typeNull, NULL},
                    resultDesc = {typeNull, NULL};
    long            index;
    DescType        returnedType;
    OSErr           err;
 
            // Coerce theObj into a token which we can use - 
            //  this may involve converting a list of tokens to a list of property tokens
    if ( typeObjectSpecifier == theObj->descriptorType )
        err = AEResolve( theObj, kAEIDoMinimum, &objTokenDesc );
    else if ( typeNull != theObj->descriptorType )  // Otherwise, just copy it
        err = AEDuplicateDesc( theObj, &objTokenDesc );
    
    if ( noErr != err ) goto done;
    
    switch ( objTokenDesc.descriptorType )
    {
        case typeMyApplProp:
            err = GetApplicationProperty( &objTokenDesc, theWantType, result );
            break;
            
        case typeMyTextProp:
            err = GetTextProperty(&objTokenDesc, result);
            break;
            
        case typeMyWindowProp:
            err = GetWindowProperty(&objTokenDesc, result);
            break;
            
        case typeMyDocumentProp:
            err = GetDocumentProperty( &objTokenDesc, theWantType, result );
            break;
            
        case typeMyMenuProp:
            err = GetMenuProperty( &objTokenDesc, theWantType, result );
            break;
            
        case typeMyMenuItemProp:
            err = GetMenuItemProperty( &objTokenDesc, theWantType, result );
            break;
            
        case typeMyText:
            GetRawDataFromDescriptor( &objTokenDesc, (Ptr)&theTextToken,
                                                sizeof(theTextToken), &tokenSize );
 
            if ( theWantType == typeChar || theWantType == typeIntlText )
                err = GetTextTextProperty( &theTextToken, result );
            else                // For OSADoEvent()
                err = GetTextTokenObjectSpecifier( &theTextToken, result );
            break;
            
        case typeAEList:
            err = AECountItems(&objTokenDesc, &index);
            if (noErr != err) goto done;
    
            for (; index > 0; index--)
            {
                err = AEGetNthDesc(&objTokenDesc, index, typeWildCard, &returnedType, &itemDesc);
    
                if (noErr == err)       // Call this function recursively if necessary
                    err = HandleGetData(&itemDesc, theWantType, &resultDesc);
                
                if (noErr == err)       // Overwrite item in list with descriptor item
                    err = AEPutDesc(&objTokenDesc, index, &resultDesc);
                                                        // objTokenDesc is just a copy anyway.
                (void)AEDisposeDesc(&itemDesc);
                (void)AEDisposeDesc(&resultDesc);
            }
            
            err = AEDuplicateDesc( &objTokenDesc, result );     // Copy list into result
            break;
            
        default:    
            err = AEDuplicateDesc( theObj, result );    // For OSADoEvent()
            break;
    }
 
done:
    (void)AEDisposeDesc( &objTokenDesc );
    
    return err;
} // HandleGetData
 
 
// Get the actual data for a text token - rather than just offset and length
// used internally.
 
OSErr   GetTextTextProperty(TextToken* theToken, AEDesc *result)
{
    TEHandle    aTEH;
    short       anOffset,
                aLength;
    OSErr       err;
    
    aTEH = TEHandleFromTextToken(theToken);
    anOffset = theToken->tokenOffset;
    aLength = theToken->tokenLength;
    
    err = BuildStyledTextDesc(aTEH, anOffset, aLength, result);
 
    return(err);
}
 
// -----------------------------------------------------------------------
//  Name:       GetTextProperty
//  Purpose:    Fills result with the requested text property.
// -----------------------------------------------------------------------
 
OSErr GetTextProperty(const AEDesc *theTokenDesc, AEDesc *result)
{
    DPtr          theDocument;
    TEHandle      theHTE;
    Str255        fontName;
    TextStyle     theTextStyle;
    short         lineHeight;
    short         fontAscent;
    TextPropToken theTextPropToken;
    Size          tokenSize;
    AEDesc        tempDesc;
    OSErr         err;
    
    err = AECoerceDesc(theTokenDesc, typeMyTextProp, &tempDesc);
    if (noErr != err) goto done;
    
    GetRawDataFromDescriptor(&tempDesc, (Ptr)&theTextPropToken,
                                    sizeof(theTextPropToken), &tokenSize);
 
    // For each property we build a descriptor to be returned as the reply.
            
    theDocument = DPtrFromWindowPtr(theTextPropToken.tokenTextToken.tokenWindow);
    theHTE = theDocument->theText;
    
    TEGetStyle(theTextPropToken.tokenTextToken.tokenOffset - 1, &theTextStyle,
                                                &lineHeight, &fontAscent, theHTE);
    
    switch (theTextPropToken.tokenProperty)
    {
        case pText:
        case pContents:
            err = GetTextTextProperty(&(theTextPropToken.tokenTextToken), result);
            break;
            
        case pFont: 
            GetFontName(theTextStyle.tsFont, fontName);
            
            err = AECreateDesc(typeChar,  (Ptr)&fontName[1], fontName[0], result);
            break;
        
        case pTextStyles: 
            err = BuildTextStylesDesc(theTextStyle.tsFace, result);
            break;
 
        case pPointSize: 
            err = CreateOffsetDescriptor(theTextStyle.tsSize, result);
            break;
 
        case pScriptTag: 
            err = CreateOffsetDescriptor(smSystemScript, result);
            break;
        
        case pColor: 
            err = AECreateDesc(typeRGBColor, (Ptr)&theTextStyle.tsColor,
                                        sizeof(theTextStyle.tsColor), result);
            break;
            
        case pLength:
            tokenSize = theTextPropToken.tokenTextToken.tokenLength;
            err = AECreateDesc(typeInteger, (Ptr)&tokenSize,
                                sizeof(tokenSize), result);
            break;
            
        case pOffset:
            tokenSize = theTextPropToken.tokenTextToken.tokenOffset;
            err = AECreateDesc(typeInteger, (Ptr)&tokenSize,
                                sizeof(tokenSize), result);
            break;
            
        default:
            err = errAEEventNotHandled;
    }
 
done:
    if (tempDesc.dataHandle)
        AEDisposeDesc(&tempDesc);
    
    return(err);
} // GetTextProperty
 
 
// -----------------------------------------------------------------------
//      Name:           GetWindowProperty
//      Purpose:        Fills result with the requested window property.
// -----------------------------------------------------------------------
 
OSErr   GetWindowProperty(const AEDesc *theTokenDesc, AEDesc *result)
{            
    WindowPropToken theWindowPropToken;
    AEDesc          tempDesc = {typeNull, NULL};
    Size            tokenSize;
    OSErr           err;
    
    err = AECoerceDesc( theTokenDesc, typeMyWindowProp, &tempDesc );
    if (noErr != err) goto done;
    
    GetRawDataFromDescriptor(&tempDesc, (Ptr)&theWindowPropToken,
                                sizeof(theWindowPropToken),  &tokenSize);
                                
    err = GetWindowTokenProperty( &theWindowPropToken, result );
 
done:
    (void)AEDisposeDesc( &tempDesc );
            
    return(err);
} // GetWindowProperty
 
 
OSErr   GetWindowTokenProperty( WindowPropToken* theToken, AEDesc *result )
{
    DescType            aType;
    Rect                aRect;
    Boolean             aBoolean;
    Str255              aString;
    long                aLong;
    WStateDataHandle    stateHandle;
    OSErr               err;
 
    switch( theToken->tokenProperty )
    {
        case pClass:
        case pDefaultType:  // ?
            aType = cWindow;
            err = AECreateDesc(typeType, (Ptr)&aType, sizeof(aType), result);
            break;
 
        case pBestType:
            if ( IsDocumentWindow( theToken->tokenWindowToken.tokenWindow ) )
                aType = cDocument;
            else
                aType = cWindow;
 
            err = AECreateDesc(typeType, (Ptr)&aType, sizeof(aType), result);
            break;
        
        case pBounds:
            aRect = (*((WindowPeek)theToken->tokenWindowToken.tokenWindow)->strucRgn)->rgnBBox;
            err = AECreateDesc(typeQDRectangle, (Ptr)&aRect, sizeof(aRect), result);
            break;
            
        case pVisible:
            aBoolean = IsVisible( theToken->tokenWindowToken.tokenWindow );
            err = AECreateDesc(typeBoolean, (Ptr)&aBoolean, sizeof(aBoolean), result);
            break;
            
        case pHasCloseBox:
            aBoolean = ((WindowPeek)theToken->tokenWindowToken.tokenWindow)->goAwayFlag;
            err = AECreateDesc(typeBoolean, (Ptr)&aBoolean, sizeof(aBoolean), result);
            break;
            
        case pIsZoomable:
            aBoolean = ((WindowPeek)theToken->tokenWindowToken.tokenWindow)->spareFlag;
            err = AECreateDesc(typeBoolean, (Ptr)&aBoolean, sizeof(aBoolean), result);
            break;
            
        case pIsZoomed:
            if (((WindowPeek)theToken->tokenWindowToken.tokenWindow)->spareFlag)
            {
                stateHandle = (WStateDataHandle)((WindowPeek)theToken->tokenWindowToken.tokenWindow)->dataHandle;
            
                HLock((Handle)stateHandle);
                aBoolean = ! EqualRect(&(*stateHandle)->userState, &(*stateHandle)->stdState);
                HUnlock((Handle)stateHandle);
            }
            else
                aBoolean = false;
                            
            err = AECreateDesc(typeBoolean, (Ptr)&aBoolean, sizeof(aBoolean), result);
            break;
        
        case pName:
            GetWTitle(theToken->tokenWindowToken.tokenWindow, aString);
            err = AECreateDesc(typeChar, (Ptr)&aString[1], aString[0], result);
            break;
            
        case pIndex:
            aLong = GetWindowIndex( theToken->tokenWindowToken.tokenWindow );
            err = AECreateDesc(typeLongInteger, (Ptr)&aLong, sizeof(aLong), result);
            break;
    
        default:
            err = errAEEventNotHandled;
    }
    
    return(err);
}
 
 
OSErr   GetDocumentProperty( const AEDesc *theTokenDesc, DescType theWantType, AEDesc *result )
{
    WindowPropToken theWindowPropToken;
    AEDesc          tempDesc = {typeNull, NULL};
    Size            tokenSize;
    OSErr           err;
    
    err = AECoerceDesc( theTokenDesc, typeMyDocumentProp, &tempDesc );
    if (noErr != err) goto done;
    
    GetRawDataFromDescriptor( &tempDesc, (Ptr)&theWindowPropToken,
                                sizeof( theWindowPropToken ),  &tokenSize );
    
    err = GetDocumentTokenProperty( &theWindowPropToken, theWantType, result );
 
done:
    (void)AEDisposeDesc( &tempDesc );
            
    return(err);
}
 
 
OSErr   GetDocumentTokenProperty( WindowPropToken* theToken, DescType theWantType, AEDesc *result )
{
    AEDesc          aDesc = { typeNull, NULL };
    DescType        aType;
    DescType        aLong;
    Boolean         aBoolean;
    DPtr            aDoc;
    TEHandle        theHTE;
    Handle          thePGXHandle;
//  Str255          aPStr;
    OSErr           err;
 
    aDoc = DPtrFromWindowPtr( theToken->tokenWindowToken.tokenWindow );
    
    switch ( theToken->tokenProperty )
    {
        case pBestType:
        case pClass:
        case pDefaultType:
            aType = cDocument;
            err = AECreateDesc( typeType, (Ptr)&aType, sizeof(aType), result );
        break;
            
        case pText:
        case pContents:
            theHTE = aDoc->theText;
            err = BuildStyledTextDesc(theHTE, 1, (**theHTE).teLength, result);
            break;
 
        case pIsModified:
            aBoolean = aDoc->dirty;
            err = AECreateDesc(typeBoolean, (Ptr)&aBoolean, sizeof( aBoolean ), result);
            break;
            
        case pIndex:
            aLong = GetDocumentIndex( theToken->tokenWindowToken.tokenWindow );
            err = AECreateDesc(typeLongInteger, (Ptr)&aLong, sizeof(aLong), result);
            break;
            
        case pPageSetup:
            if (! gGXIsPresent)
            {
                HLock((Handle)aDoc->thePrintSetup);
                err = AECreateDesc(typeTPrint, (Ptr)*(aDoc->thePrintSetup),
                                                                sizeof(TPrint), result);
                HUnlock((Handle)aDoc->thePrintSetup);
            }
            else
                err = errAEEventNotHandled;                      
            break;
 
        case pGXPageSetup:
            if ( gGXIsPresent )
            {
                thePGXHandle = NewHandle( 0 );
                GXFlattenJobToHdl( aDoc->documentJob, thePGXHandle );
    
                HLock( thePGXHandle );
                
                err = AECreateDesc( typeTPrint, *thePGXHandle,
                                        GetHandleSize(thePGXHandle), result );
                                                             
                HUnlock( thePGXHandle );                                                                             
                DisposeHandle( thePGXHandle );
            }
            else
                err = errAEEventNotHandled;                  
            break;
            
        case pSelection:
            err = MakeSelectedTextObj( theToken->tokenWindowToken.tokenWindow,
                                                                aDoc->theText, result );
            break;
 
        case pScript:
            if ( kOSANullScript == aDoc->theScriptID )
            {
                err = errAENoSuchObject;
                goto done;
            }
            
            err = GetScriptDesc( aDoc->theScriptID, theWantType, result );
            break;
 
        default:
            err = GetWindowTokenProperty( theToken, result );
    }
 
done:
    (void)AEDisposeDesc( &aDesc );
            
    return err;
}
 
// -----------------------------------------------------------------------
//      Name:           GetApplicationProperty
//      Purpose:        Fills result with the requested application property.
// -----------------------------------------------------------------------
     
OSErr   GetApplicationProperty( const AEDesc *theTokenDesc, DescType theWantType, AEDesc *result )
{
    Boolean             isFront;
    AppPropToken        theAppPropToken;
    AEDesc              aDesc = {typeNull, NULL},
                        nullDesc = {typeNull, NULL};
    Size                tokenSize;
    DescType            theType;
    short               refNum;
    Handle              aHandle;
    OSErr               err;
    
    err = AECoerceDesc(theTokenDesc, typeMyApplProp, &aDesc);
    if (noErr != err) goto done;
    
    GetRawDataFromDescriptor(&aDesc, (Ptr)&theAppPropToken,
                                        sizeof(theAppPropToken), &tokenSize);
      
    switch ( theAppPropToken.tokenProperty )
    {
        case pBestType:     // Return the null descriptor representing
        case pDefaultType:  // the application.
            err = AEDuplicateDesc(&nullDesc, result);
            break;
        
        case pClass:
            theType = cApplication;
            err = AECreateDesc(typeType, (Ptr)&theType, sizeof(DescType), result);
            break;
        
        case pName:
                // We got the name and FSSpec for our application
                //  in InitApplicationRec().
            err = AECreateDesc( typeChar, (Ptr)&gAppRec.theName[1], gAppRec.theName[0], result );
            break;
        
        case pIsFrontProcess:
            isFront = ! gInBackground;
            err = AECreateDesc(typeBoolean, (Ptr)&isFront, sizeof(isFront), result);
            break;
 
        case pVersion:
            refNum = CurResFile();  // save current resource
            UseResFile(gRefNum);    // set this resource to be current
            aHandle = (Handle)Get1Resource((ResType)'vers', 1);
            HLock(aHandle);
            err = AECreateDesc(typeVersion, *aHandle, GetHandleSize(aHandle), result);
            HUnlock(aHandle);
            UseResFile(refNum);     // reset back to resource previously set
            break;
            
        case pResults:
            err = MakeDocumentObj( GetResultsWindPtr( ), result );
            break;
 
        case pScript:
            if ( kOSANullScript == gAppRec.theScriptID )
            {
                err = errAENoSuchObject;
                goto done;
            }
            
            err = GetScriptDesc( gAppRec.theScriptID, theWantType, result );
            break;
 
        default:   // We don't handle the requested property.
            err = errAEEventNotHandled;
    }
 
done:
    (void)AEDisposeDesc( &aDesc );
            
    return err;
} // GetApplicationProperty
 
 
OSErr   GetMenuProperty( const AEDesc *theTokenDesc, DescType theWantType, AEDesc *result )
{
    Str255              aPStr;
    MenuPropToken       thePropToken;
    MenuItemToken       aMenuItemToken;
    AEDesc              aDesc = {typeNull, NULL};
    Size                tokenSize;
    DescType            aType;
    MenuScriptRecPtr    aMenuRecPtr;
    OSErr               err;
    
    err = AECoerceDesc( theTokenDesc, typeMyMenuProp, &aDesc );
    if (noErr != err) goto done;
    
    GetRawDataFromDescriptor( &aDesc, (Ptr)&thePropToken,
                                        sizeof( thePropToken ), &tokenSize );
      
    switch ( thePropToken.tokenProperty )
    {
        case pBestType:
        case pDefaultType:
        case pClass:
            aType = cMenu;
            err = AECreateDesc( typeType, (Ptr)&aType, sizeof( DescType ), result );
            break;
        
        case pName:
            GetMenuName( &thePropToken.token, aPStr );
 
            err = AECreateDesc( typeChar, (Ptr)&aPStr[1], aPStr[0], result );
            break;
            
        case pMenuID:
            err = AECreateDesc( typeShortInteger, (Ptr)&thePropToken.token.tokenID,
                                            sizeof( thePropToken.token.tokenID ), result );
            break;
 
        case pScript:
                // Get a Ptr to the script for the whole menu
            aMenuRecPtr = GetMenuScriptRecPtr( thePropToken.token.tokenID * 32 );
            if ( ! aMenuRecPtr || kOSANullScript == aMenuRecPtr->theScriptID )
            {
                err = errAENoSuchObject;
                goto done;
            }
            
            err = GetScriptDesc( aMenuRecPtr->theScriptID, theWantType, result );
            break;
            
            
        case pSelection:
            aMenuItemToken.tokenItem = GetScriptActiveItem( );
            
            if ( 0 == aMenuItemToken.tokenItem )
                aMenuItemToken.tokenItem = 1;
            
            if ( 0 != aMenuItemToken.tokenItem )    
            {                   // A selection is only current while executing a command
                                //  that has an associated script.
                aMenuItemToken.tokenMenuToken = thePropToken.token;
                err = MakeMenuItemSpecifier( &aMenuItemToken, result );
            }
            else
                err = errAENoSuchObject;
            break;
 
        default:   // We don't handle the requested property.
            err = errAEEventNotHandled;
    }
 
done:
    (void)AEDisposeDesc( &aDesc );
            
    return(err);
}
 
 
OSErr   GetMenuItemProperty( const AEDesc *theTokenDesc, DescType theWantType, AEDesc *result )
{
    Str255              aPStr;
    MenuItemPropToken   thePropToken;
    AEDesc              aDesc = {typeNull, NULL};
    Size                tokenSize;
    DescType            aType;
    MenuScriptRecPtr    aMenuRecPtr;
    OSErr               err;
    
    err = AECoerceDesc( theTokenDesc, typeMyMenuItemProp, &aDesc );
    if (noErr != err) goto done;
    
    GetRawDataFromDescriptor( &aDesc, (Ptr)&thePropToken,
                                        sizeof( thePropToken ), &tokenSize );
      
    switch ( thePropToken.tokenProperty )
    {
        case pBestType:     // Return the null descriptor representing
        case pDefaultType:  // the application.
        case pClass:
            aType = cMenuItem;
            err = AECreateDesc( typeType, (Ptr)&aType, sizeof( DescType ), result );
            break;
        
        case pName:
            GetMenuItemName( &thePropToken.token, aPStr );
 
            err = AECreateDesc( typeChar, (Ptr)&aPStr[1], aPStr[0], result );
            break;
            
        case pItemNumber:
            err = AECreateDesc( typeShortInteger, (Ptr)&thePropToken.token.tokenItem,
                                        sizeof( thePropToken.token.tokenItem ), result );
            break;
            
        case pEnabled:
            err = errAEEventNotHandled;
            break;
 
        case pScript:
                // Get a Ptr to the script for the menu item
            aMenuRecPtr = GetMenuScriptRecPtr( thePropToken.token.tokenMenuToken.tokenID * 32
                                                + thePropToken.token.tokenItem );
            if ( ! aMenuRecPtr || kOSANullScript == aMenuRecPtr->theScriptID )
            {
                err = errAENoSuchObject;
                goto done;
            }
            
            err = GetScriptDesc( aMenuRecPtr->theScriptID, theWantType, result );
            break;
 
        default:   // We don't handle the requested property.
            err = errAEEventNotHandled;
    }
 
done:
    (void)AEDisposeDesc( &aDesc );
            
    return(err);
}