// A proper object descriptor has 4 parts: // - What class it is // - How it is being identified (in our case an ID number, specified by formUniqueID) // - The identification itself // - The parent of the object OSErr CreateAEDescFromID(unsigned int id_num, DescType object_type, AEDesc* item_desc) { AEDesc item_record; unsigned int form = formUniqueID; OSStatus err; err = AECreateList(NULL, 0, true, &item_record); if (err == noErr) { AERecord * record = &item_record; err = AEPutKeyPtr(record, keyAEDesiredClass, cType, &object_type, sizeof(object_type)); err |= AEPutKeyPtr(record, keyAEContainer, typeNull, NULL, 0); // No parent err |= AEPutKeyPtr(record, keyAEKeyForm, cEnumeration, &form, sizeof(form)); err |= AEPutKeyPtr(record, keyAEKeyData, typeUInt32, &id_num, sizeof(id_num)); if (err == noErr) { err = AECoerceDesc(record, typeObjectSpecifier, item_desc); } AEDisposeDesc(&item_record); } return err; }
// ----------------------------------------------------------------------------- // CreateSampleSubmenu // ----------------------------------------------------------------------------- static OSStatus CreateSampleSubmenu( AEDescList* ioCommandList) { OSStatus theError = noErr; AEDescList theSubmenuCommands = { typeNull, NULL }; AERecord theSupercommand = { typeNull, NULL }; Str255 theSupercommandText = "\pSubmenu Here"; // the first thing we should do is create an AEDescList of // subcommands // set up the AEDescList theError = AECreateList( NULL, 0, false, &theSubmenuCommands ); require_noerr( theError, CreateSampleSubmenu_Complete_fail ); // stick some commands in this subcommand list theError = AddCommandToAEDescList( "\pSubcommand 1", kTextEncodingMacRoman, typeChar, 1001, 0, 0, &theSubmenuCommands ); require_noerr( theError, CreateSampleSubmenu_CreateDesc_fail ); // another theError = AddCommandToAEDescList( "\pAnother Subcommand", kTextEncodingMacRoman, typeChar, 1002, 0, 0, &theSubmenuCommands ); require_noerr( theError, CreateSampleSubmenu_fail ); // yet another theError = AddCommandToAEDescList( "\pLast One", kTextEncodingMacRoman, typeChar, 1003, 0, 0, &theSubmenuCommands); require_noerr( theError, CreateSampleSubmenu_fail ); // now, we need to create the supercommand which will "own" the // subcommands. The supercommand lives in the root command list. // this looks very much like the AddCommandToAEDescList function, // except that instead of putting a command ID in the record, // we put in the subcommand list. // create an apple event record for our supercommand theError = AECreateList( NULL, 0, true, &theSupercommand ); require_noerr( theError, CreateSampleSubmenu_fail ); // stick the command text into the aerecord theError = AEPutKeyPtr(&theSupercommand, keyAEName, typeChar, &theSupercommandText[1], StrLength( theSupercommandText ) ); require_noerr( theError, CreateSampleSubmenu_fail ); // stick the subcommands into into the AERecord theError = AEPutKeyDesc(&theSupercommand, keyContextualMenuSubmenu, &theSubmenuCommands); require_noerr( theError, CreateSampleSubmenu_fail ); // stick the supercommand into the list of commands that we are // passing back to the CMM theError = AEPutDesc( ioCommandList, // the list we're putting our command into 0, // stick this command onto the end of our list &theSupercommand); // the command I'm putting into the list // clean up after ourself CreateSampleSubmenu_fail: AEDisposeDesc(&theSubmenuCommands); CreateSampleSubmenu_CreateDesc_fail: AEDisposeDesc(&theSupercommand); CreateSampleSubmenu_Complete_fail: return theError; } // CreateSampleSubmenu
// ----------------------------------------------------------------------------- // AddCommandToAEDescList // ----------------------------------------------------------------------------- static OSStatus AddCommandToAEDescList( ConstStr255Param inCommandString, TextEncoding inEncoding, DescType inDescType, SInt32 inCommandID, MenuItemAttributes inAttributes, UInt32 inModifiers, AEDescList* ioCommandList) { OSStatus theError = noErr; AERecord theCommandRecord = { typeNull, NULL }; printf( "AddCommandToAEDescList: Trying to add an item.\n" ); // create an apple event record for our command theError = AECreateList( NULL, kAEDescListFactorNone, true, &theCommandRecord ); require_noerr( theError, AddCommandToAEDescList_fail ); // stick the command text into the AERecord if ( inCommandString != NULL ) { if ( inDescType == typeChar ) { theError = AEPutKeyPtr( &theCommandRecord, keyAEName, typeChar, &inCommandString[1], StrLength( inCommandString ) ); require_noerr( theError, AddCommandToAEDescList_fail ); } else if ( inDescType == typeStyledText ) { AERecord textRecord; WritingCode writingCode; AEDesc textDesc; theError = AECreateList( NULL, kAEDescListFactorNone, true, &textRecord ); require_noerr( theError, AddCommandToAEDescList_fail ); theError = AEPutKeyPtr( &textRecord, keyAEText, typeChar, &inCommandString[1], StrLength( inCommandString ) ); require_noerr( theError, AddCommandToAEDescList_fail ); RevertTextEncodingToScriptInfo( inEncoding, &writingCode.theScriptCode, &writingCode.theLangCode, NULL ); theError = AEPutKeyPtr( &textRecord, keyAEScriptTag, typeIntlWritingCode, &writingCode, sizeof( writingCode ) ); require_noerr( theError, AddCommandToAEDescList_fail ); theError = AECoerceDesc( &textRecord, typeStyledText, &textDesc ); require_noerr( theError, AddCommandToAEDescList_fail ); theError = AEPutKeyDesc( &theCommandRecord, keyAEName, &textDesc ); require_noerr( theError, AddCommandToAEDescList_fail ); AEDisposeDesc( &textRecord ); } else if ( inDescType == typeIntlText ) { IntlText* intlText; ByteCount size = sizeof( IntlText ) + StrLength( inCommandString ) - 1; // create an IntlText structure with the text and script intlText = (IntlText*) malloc( size ); RevertTextEncodingToScriptInfo( inEncoding, &intlText->theScriptCode, &intlText->theLangCode, NULL ); BlockMoveData( &inCommandString[1], &intlText->theText, StrLength( inCommandString ) ); theError = AEPutKeyPtr( &theCommandRecord, keyAEName, typeIntlText, intlText, size ); free( (char*) intlText ); require_noerr( theError, AddCommandToAEDescList_fail ); } else if ( inDescType == typeUnicodeText ) { CFStringRef str = CFStringCreateWithPascalString( NULL, inCommandString, inEncoding ); if ( str != NULL ) { Boolean doFree = false; CFIndex sizeInChars = CFStringGetLength( str ); CFIndex sizeInBytes = sizeInChars * sizeof( UniChar ); const UniChar* unicode = CFStringGetCharactersPtr( str ); if ( unicode == NULL ) { doFree = true; unicode = (UniChar*) malloc( sizeInBytes ); CFStringGetCharacters( str, CFRangeMake( 0, sizeInChars ), (UniChar*) unicode ); } theError = AEPutKeyPtr( &theCommandRecord, keyAEName, typeUnicodeText, unicode, sizeInBytes ); CFRelease( str ); if ( doFree ) free( (char*) unicode ); require_noerr( theError, AddCommandToAEDescList_fail ); } } else if ( inDescType == typeCFStringRef ) { CFStringRef str = CFStringCreateWithPascalString( NULL, inCommandString, inEncoding ); if ( str != NULL ) { theError = AEPutKeyPtr( &theCommandRecord, keyAEName, typeCFStringRef, &str, sizeof( str ) ); require_noerr( theError, AddCommandToAEDescList_fail ); // do not release the string; the Contextual Menu Manager will release it for us } } } // stick the command ID into the AERecord if ( inCommandID != 0 ) { theError = AEPutKeyPtr( &theCommandRecord, keyContextualMenuCommandID, typeLongInteger, &inCommandID, sizeof( inCommandID ) ); require_noerr( theError, AddCommandToAEDescList_fail ); } // stick the attributes into the AERecord if ( inAttributes != 0 ) { theError = AEPutKeyPtr( &theCommandRecord, keyContextualMenuAttributes, typeLongInteger, &inAttributes, sizeof( inAttributes ) ); require_noerr( theError, AddCommandToAEDescList_fail ); } // stick the modifiers into the AERecord if ( inModifiers != 0 ) { theError = AEPutKeyPtr( &theCommandRecord, keyContextualMenuModifiers, typeLongInteger, &inModifiers, sizeof( inModifiers ) ); require_noerr( theError, AddCommandToAEDescList_fail ); } // stick this record into the list of commands that we are // passing back to the CMM theError = AEPutDesc( ioCommandList, // the list we're putting our command into 0, // stick this command onto the end of our list &theCommandRecord ); // the command I'm putting into the list AddCommandToAEDescList_fail: // clean up after ourself; dispose of the AERecord AEDisposeDesc( &theCommandRecord ); return theError; } // AddCommandToAEDescList