Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
SampleCMPlugIn.c
// |
// File: SampleCMPlugIn.c of SampleCMPlugIn |
// |
// Created: Thu Jan 22 2004 |
// |
// Contains: Sample source for a contextual menu plugin for the Finder |
// |
// Notes: This version adds support for menu attributes and modifiers to the Command_AddToAEDescList |
// routine. It also installs an application event handler for the kEventClassMenu, kEventMenuPopulate |
// event. This handler is used to add icons to the "Subcommand" menu items. |
// Sample code was also added to disable the CMM when the current app isn't the Finder. |
// |
// Copyright: Copyright © 2005 Apple Computer, Inc. ( DTS ), All Rights Reserved |
// |
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
// ( "Apple" ) in consideration of your agreement to the following terms, and your |
// use, installation, modification or redistribution of this Apple software |
// constitutes acceptance of these terms. If you do not agree with these terms, |
// please do not use, install, modify or redistribute this Apple software. |
// |
// In consideration of your agreement to abide by the following terms, and subject |
// to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs |
// copyrights in this original Apple software ( the "Apple Software" ), to use, |
// reproduce, modify and redistribute the Apple Software, with or without |
// modifications, in source and/or binary forms; provided that if you redistribute |
// the Apple Software in its entirety and without modifications, you must retain |
// this notice and the following text and disclaimers in all such redistributions of |
// the Apple Software. Neither the name, trademarks, service marks or logos of |
// Apple Computer, Inc. may be used to endorse or promote products derived from the |
// Apple Software without specific prior written permission from Apple. Except as |
// expressly stated in this notice, no other rights or licenses, express or implied, |
// are granted by Apple herein, including but not limited to any patent rights that |
// may be infringed by your derivative works or by other works in which the Apple |
// Software may be incorporated. |
// |
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
// WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
// PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
// COMBINATION WITH YOUR PRODUCTS. |
// |
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) |
// ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
// OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
// ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// |
// **************************************************** |
#pragma mark - |
#pragma mark * complation directives * |
// ---------------------------------------------------- |
#define LOG_ENTRY_POINTS TRUE // set this TRUE to log routine entry points to the console |
#define FINDER_ONLY TRUE // set this TRUE if you want your CMM to only appear in the Finder |
// **************************************************** |
#pragma mark - |
#pragma mark * includes & imports * |
// ---------------------------------------------------- |
#include <Carbon/Carbon.h> |
#include <CoreFoundation/CoreFoundation.h> |
#include <CoreFoundation/CFPlugInCOM.h> |
#include <ApplicationServices/ApplicationServices.h> |
#include <CoreServices/CoreServices.h> |
// **************************************************** |
#pragma mark - |
#pragma mark * typedef's, struct's, enums, defines, etc. * |
// ---------------------------------------------------- |
#define kMyBundleIdentifier CFSTR( "com.apple.SampleCMPlugIn" ) |
// "C52C2566-3DC1-11D5-BBA3-003065B300BC" |
#define kSampleCMPlugIn_FactoryID \ |
( CFUUIDGetConstantUUIDWithBytes( NULL, \ |
0xC5, 0x2C, 0x25, 0x66, 0x3D, 0xC1, 0x11, 0xD5, \ |
0xBB, 0xA3, 0x00, 0x30, 0x65, 0xB3, 0x00, 0xBC ) ) |
// The layout for an instance of SampleCMPlugInType. |
typedef struct SampleCMPlugIn_struct { |
ContextualMenuInterfaceStruct * cmInterface; |
CFUUIDRef factoryID; |
UInt32 refCount; |
} SampleCMPlugIn_rec, *SampleCMPlugIn_ptr; |
// **************************************************** |
#pragma mark - |
#pragma mark * interface function prototypes * |
// ---------------------------------------------------- |
static HRESULT SampleCMPlugIn_QueryInterface( void * thisInstance, REFIID iid, LPVOID * ppv ); |
static ULONG SampleCMPlugIn_AddRef( void *thisInstance ); |
static ULONG SampleCMPlugIn_Release( void *thisInstance ); |
static OSStatus SampleCMPlugIn_ExamineContext( void * thisInstance, const AEDesc* inContext, AEDescList* outCommandPairs ); |
static OSStatus SampleCMPlugIn_HandleSelection( void * thisInstance, AEDesc* inContext, SInt32 inCommandID ); |
static void SampleCMPlugIn_PostMenuCleanup( void *thisInstance ); |
// **************************************************** |
#pragma mark - |
#pragma mark * local ( static ) function prototypes * |
// ---------------------------------------------------- |
static SampleCMPlugIn_ptr SampleCMPlugIn_Alloc( CFUUIDRef inFactoryID ); |
static void SampleCMPlugIn_Dealloc( SampleCMPlugIn_ptr thisInstance ); |
static char * Copy_CFStringRefToCString( CFStringRef pCFStringRef ); |
static OSStatus Command_AddToAEDescList( CFStringRef inCommandCFStringRef, SInt32 inCommandID, MenuItemAttributes inAttributes, UInt32 inModifiers, AEDescList* ioCommandList ); |
static OSStatus FileSubMenu_Create( const AEDesc* inContext, AEDescList* ioCommandList ); |
static OSStatus FileSubMenu_Handle( const AEDesc* inContext, SInt32 inCommandID ); |
static OSStatus SampleSubMenu_Create( AEDescList* ioCommandList ); |
static OSStatus SampleSubMenu_Handle( const AEDesc* inContext, SInt32 inCommandID ); |
static pascal OSStatus MenuEvent_Handle( EventHandlerCallRef inEventHandlerCallRef, EventRef inEventRef, void * inUserData ); |
// **************************************************** |
#pragma mark - |
#pragma mark * exported globals * |
// ---------------------------------------------------- |
// **************************************************** |
#pragma mark - |
#pragma mark * local ( static ) globals * |
// ---------------------------------------------------- |
static SInt32 gNumCommandIDs = 0; |
static Boolean gHasAttributeAndModifierKeys = FALSE; |
static EventHandlerUPP gMenuEventHandlerUPP = NULL; |
static EventHandlerRef gMenuEventHandlerRef = NULL; |
static const char * gSubCommandCStrings[] = {"First Subcommand", "Second Subcommand", "Third Subcommand", "Fourth Subcommand"}; |
// **************************************************** |
#pragma mark - |
#pragma mark * exported function implementations * |
// ---------------------------------------------------- |
// ---------------------------------------------------- |
// SampleCMPlugIn_Factory |
// ---------------------------------------------------- |
// Implementation of the factory function for this type. |
// |
extern void * SampleCMPlugIn_Factory( CFAllocatorRef allocator, CFUUIDRef typeID ); |
void * SampleCMPlugIn_Factory( CFAllocatorRef allocator, CFUUIDRef typeID ) |
{ |
#pragma unused ( allocator ) |
#if LOG_ENTRY_POINTS |
printf( "SampleCMPlugIn_Factory( %p, %p )\n", allocator, typeID ); |
fflush( stdout ); |
#endif LOG_ENTRY_POINTS |
void * result = NULL; |
// If correct type is being requested, allocate an |
// instance of TestType and return the IUnknown interface. |
if ( CFEqual( typeID, kContextualMenuTypeID ) ) { |
result = ( void * ) SampleCMPlugIn_Alloc( kSampleCMPlugIn_FactoryID ); |
} |
return result; |
} |
// **************************************************** |
#pragma mark - |
#pragma mark * local ( static ) function implementations * |
// ---------------------------------------------------- |
// ----------------------------------------------------------------------------- |
// SampleCMInterface definition |
// ----------------------------------------------------------------------------- |
// The Contextual Menu Interface function table. |
// |
static ContextualMenuInterfaceStruct gSampleCMInterface = |
{ |
// Required padding for COM |
NULL, |
// These three are the required COM functions |
SampleCMPlugIn_QueryInterface, |
SampleCMPlugIn_AddRef, |
SampleCMPlugIn_Release, |
// Interface implementation |
SampleCMPlugIn_ExamineContext, |
SampleCMPlugIn_HandleSelection, |
SampleCMPlugIn_PostMenuCleanup |
}; |
// **************************************************** |
#pragma mark - |
#pragma mark * interface function implementations * |
// ---------------------------------------------------- |
// ----------------------------------------------------------------------------- |
// SampleCMPlugIn_QueryInterface |
// ----------------------------------------------------------------------------- |
// Implementation of the IUnknown QueryInterface function. |
// |
static HRESULT SampleCMPlugIn_QueryInterface( void * thisInstance, REFIID iid, LPVOID * ppv ) |
{ |
#if LOG_ENTRY_POINTS |
printf( "SampleCMPlugIn_QueryInterface( %p, %p, %p )\n", thisInstance, &iid, ppv ); |
fflush( stdout ); |
#endif |
HRESULT result = S_OK; // assume success |
// Create a CoreFoundation UUIDRef for the requested interface. |
CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes( NULL, iid ); |
// Test the requested ID against the valid interfaces. |
if ( CFEqual( interfaceID, kContextualMenuInterfaceID ) ) { |
// If the TestInterface was requested, bump the ref count, |
// set the ppv parameter equal to the instance, and |
// return good status. |
SampleCMPlugIn_AddRef( thisInstance ); |
*ppv = thisInstance; |
CFRelease( interfaceID ); |
} else if ( CFEqual( interfaceID, IUnknownUUID ) ) { |
// If the IUnknown interface was requested, same as above. |
SampleCMPlugIn_AddRef( thisInstance ); |
*ppv = thisInstance; |
CFRelease( interfaceID ); |
} else { |
// Requested interface unknown, bail with result. |
*ppv = NULL; |
CFRelease( interfaceID ); |
result = E_NOINTERFACE; |
} |
return result; |
} |
// ----------------------------------------------------------------------------- |
// SampleCMPlugIn_AddRef |
// ----------------------------------------------------------------------------- |
// Implementation of reference counting for this type. Whenever an interface |
// is requested, bump the refCount for the instance. NOTE: returning the |
// refcount is a convention but is not required so don't rely on it. |
// |
static ULONG SampleCMPlugIn_AddRef( void * thisInstance ) |
{ |
#if LOG_ENTRY_POINTS |
printf( "SampleCMPlugIn_AddRef( %p )\n", thisInstance ); |
fflush( stdout ); |
#endif |
( ( SampleCMPlugIn_ptr ) thisInstance )->refCount += 1; |
return ( ( SampleCMPlugIn_ptr ) thisInstance )->refCount; |
} |
// ----------------------------------------------------------------------------- |
// SampleCMPlugIn_Release |
// ----------------------------------------------------------------------------- |
// When an interface is released, decrement the refCount. |
// If the refCount goes to zero, deallocate the instance. |
// |
static ULONG SampleCMPlugIn_Release( void * thisInstance ) |
{ |
#if LOG_ENTRY_POINTS |
printf( "SampleCMPlugIn_Release( %p )\n", thisInstance ); |
fflush( stdout ); |
#endif |
ULONG result = 0; |
( (SampleCMPlugIn_ptr ) thisInstance )->refCount -= 1; |
if ( (( SampleCMPlugIn_ptr ) thisInstance )->refCount == 0 ) { |
SampleCMPlugIn_Dealloc( (SampleCMPlugIn_ptr ) thisInstance ); |
} else { |
result = ( (SampleCMPlugIn_ptr ) thisInstance )->refCount; |
} |
return result; |
} |
// ----------------------------------------------------------------------------- |
// SampleCMPlugIn_ExamineContext |
// ----------------------------------------------------------------------------- |
// The implementation of the ExamineContext test interface function. |
// |
static OSStatus SampleCMPlugIn_ExamineContext( void * thisInstance, |
const AEDesc * inContext, |
AEDescList * outCommandPairs ) |
{ |
#if LOG_ENTRY_POINTS |
printf( "SampleCMPlugIn_ExamineContext( %p, %p, %p )\n", thisInstance, inContext, outCommandPairs ); |
fflush( stdout ); |
#endif |
OSStatus result = noErr; |
CFStringRef bundleCFStringRef = CFSTR( "com.apple.SampleCMPlugIn" ); |
CFBundleRef myCFBundleRef = CFBundleGetBundleWithIdentifier( bundleCFStringRef ); |
#if FINDER_ONLY |
ProcessInfoRec tPIR; |
ProcessSerialNumber tPSN = {0, kCurrentProcess}; |
tPIR.processInfoLength = sizeof( ProcessInfoRec ); |
tPIR.processName = nil; |
tPIR.processAppSpec = nil; |
OSStatus status = GetProcessInformation( &tPSN, &tPIR ); |
if ( noErr == status ) { |
if ( tPIR.processSignature != 'MACS' || |
tPIR.processType != 'FNDR' ) { |
fprintf( stderr, "\nNot the Finder!" ); fflush( stderr ); |
return noErr; |
} |
} else { |
fprintf( stderr, "\nGetProcessInformation error: %ld.", status ); fflush( stderr ); |
} |
#endif |
// Install Carbon ( menu ) event handler |
const EventTypeSpec menuEvents[] = { |
{kEventClassMenu, kEventMenuPopulate}, |
}; |
if ( !gMenuEventHandlerUPP ) { |
gMenuEventHandlerUPP = NewEventHandlerUPP( MenuEvent_Handle ); |
} |
InstallApplicationEventHandler( gMenuEventHandlerUPP, GetEventTypeCount( menuEvents ), menuEvents, NULL, &gMenuEventHandlerRef ); |
// initilize the command id sequence |
gNumCommandIDs = 0; |
// Verify that we've got an up-to-date CMM |
verify_noerr( Gestalt( gestaltContextualMenuAttr, &result ) ); |
if ( ( result & ( 1 << gestaltContextualMenuHasAttributeAndModifierKeys ) ) != 0 ) { |
printf( "\nSampleCMPlugIn: CMM supports Attributes and Modifiers keys." ); |
gHasAttributeAndModifierKeys = TRUE; |
} else { |
printf( "\nSampleCMPlugIn: CMM DOES NOT support Attributes and Modifiers keys" ); |
gHasAttributeAndModifierKeys = FALSE; |
} |
// this is a quick sample that looks for text in the context descriptor |
// make sure the descriptor isn't null |
if ( inContext ) { |
AEDesc theAEDesc = { typeNull, NULL }; |
CFStringRef tempCFStringRef; |
Str32 tStr32; |
Command_AddToAEDescList( CFSTR( "-" ), ++gNumCommandIDs, kMenuItemAttrSeparator, kMenuNoModifiers, outCommandPairs ); |
if ( myCFBundleRef ) { |
tempCFStringRef = CFBundleGetValueForInfoDictionaryKey( myCFBundleRef, CFSTR( "CFBundleName" )); |
tempCFStringRef = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR( "Inside '%@'" ), tempCFStringRef ); |
if ( tempCFStringRef ) { |
Command_AddToAEDescList( tempCFStringRef, ++gNumCommandIDs, 0, kMenuNoModifiers, outCommandPairs ); |
CFRelease( tempCFStringRef ); |
} |
} |
// This shows how to use the keyContextualMenuAttributes & keyContextualMenuModifiers |
if ( gHasAttributeAndModifierKeys ) { |
Command_AddToAEDescList( CFSTR( "a disabled item" ), ++gNumCommandIDs, kMenuItemAttrDisabled, kMenuNoModifiers, outCommandPairs ); |
Command_AddToAEDescList( CFSTR( "Option key up" ), ++gNumCommandIDs, kMenuItemAttrDynamic, kMenuNoModifiers, outCommandPairs ); |
Command_AddToAEDescList( CFSTR( "Option key down" ), ++gNumCommandIDs, kMenuItemAttrDynamic, kMenuOptionModifier, outCommandPairs ); |
Command_AddToAEDescList( CFSTR( "Another Option key up" ), ++gNumCommandIDs, kMenuItemAttrNotPreviousAlternate | kMenuItemAttrDynamic, kMenuNoModifiers, outCommandPairs ); |
Command_AddToAEDescList( CFSTR( "Another Option key down" ), ++gNumCommandIDs, kMenuItemAttrNotPreviousAlternate | kMenuItemAttrDynamic, kMenuOptionModifier, outCommandPairs ); |
Command_AddToAEDescList( CFSTR( "This should be hidden!" ), 0, kMenuItemAttrHidden, kMenuNoModifiers, outCommandPairs ); |
Command_AddToAEDescList( CFSTR( "a separator item" ), 0, kMenuItemAttrSeparator, kMenuNoModifiers, outCommandPairs ); |
Command_AddToAEDescList( CFSTR( "a section header" ), 0, kMenuItemAttrSectionHeader, kMenuNoModifiers, outCommandPairs ); |
Command_AddToAEDescList( CFSTR( "-A meta-ignored item" ), ++gNumCommandIDs, kMenuItemAttrIgnoreMeta, kMenuNoModifiers, outCommandPairs ); |
Command_AddToAEDescList( CFSTR( "-A meta separator item" ), 0, 0, kMenuNoModifiers, outCommandPairs ); |
Command_AddToAEDescList( CFSTR( "a modified item\\I" ), ++gNumCommandIDs, 0, kMenuOptionModifier, outCommandPairs ); |
Command_AddToAEDescList( CFSTR( "an unmodified item\\I" ), ++gNumCommandIDs, 0, kMenuNoModifiers, outCommandPairs ); |
} |
// tell the raw type of the descriptor |
sprintf( ( char * ) tStr32, "raw type: '%4.4s'", ( Ptr ) &inContext->descriptorType ); |
tempCFStringRef = CFStringCreateWithCString( kCFAllocatorDefault, ( Ptr ) tStr32, kCFStringEncodingASCII ); |
Command_AddToAEDescList( tempCFStringRef, 0, kMenuNoModifiers, ++gNumCommandIDs, outCommandPairs ); |
CFRelease( tempCFStringRef ); |
if ( typeAEList == inContext->descriptorType ) |
FileSubMenu_Create( inContext, outCommandPairs ); |
else if ( typeAlias == inContext->descriptorType ) { |
if ( AECoerceDesc( inContext, typeAEList, &theAEDesc ) == noErr ) { |
FileSubMenu_Create( &theAEDesc, outCommandPairs ); |
AEDisposeDesc( &theAEDesc ); |
} else { |
fprintf( stderr, "\nSampleCMPlugIn_ExamineContext: Unable to coerce to list." ); fflush( stderr ); |
// add a text only command to our command list |
Command_AddToAEDescList( CFSTR( "Can't Coerce alias to list." ), ++gNumCommandIDs, 0, kMenuNoModifiers, outCommandPairs ); |
} |
} else { |
// try to get text out of the context descriptor; make sure to |
// coerce it, cuz the app may have passed an object specifier or |
// styled text, etc. |
if ( AECoerceDesc( inContext, typeUTF8Text, &theAEDesc ) == noErr ) { |
// add a text only command to our command list |
Command_AddToAEDescList( CFSTR( "We got text!" ), ++gNumCommandIDs, 0, kMenuNoModifiers, outCommandPairs ); |
AEDisposeDesc( &theAEDesc ); |
} else { |
fprintf( stderr, "\nSampleCMPlugIn_ExamineContext: Unable to coerce to text." ); fflush( stderr ); |
// add a text only command to our command list |
Command_AddToAEDescList( CFSTR( "Can't Coerce." ), ++gNumCommandIDs, 0, kMenuNoModifiers, outCommandPairs ); |
} |
} |
// Just for kicks, lets create a SubMenu for our plugin |
SampleSubMenu_Create( outCommandPairs ); |
Command_AddToAEDescList( CFSTR( "bottom separator item" ), 0, kMenuItemAttrSeparator, kMenuNoModifiers, outCommandPairs ); |
} else { |
fprintf( stderr, "\nSampleCMPlugIn_ExamineContext: NULL descriptor?" ); fflush( stderr ); |
// we have a null descriptor |
Command_AddToAEDescList( CFSTR( "NULL Descriptor" ), ++gNumCommandIDs, 0, kMenuNoModifiers, outCommandPairs ); |
} |
#if FALSE // Set this TRUE to printf the outCommandPairs |
Handle strHdl; |
result = AEPrintDescToHandle( outCommandPairs, &strHdl ); |
if ( noErr == result ) { |
char nul = '\0'; |
PtrAndHand( &nul, strHdl, 1 ); |
printf( "\nSampleCMPlugIn_ExamineContext: outCommandPairs: \"%s\".", *strHdl ); |
fflush( stdout ); |
DisposeHandle( strHdl ); |
} |
#endif |
fflush( stdout ); |
return noErr; |
} // SampleCMPlugIn_ExamineContext |
// ----------------------------------------------------------------------------- |
// HandleSelection |
// ----------------------------------------------------------------------------- |
// The implementation of the HandleSelection test interface function. |
// |
static OSStatus SampleCMPlugIn_HandleSelection( void * thisInstance, |
AEDesc * inContext, |
SInt32 inCommandID ) |
{ |
#if LOG_ENTRY_POINTS |
printf( "\nSampleCMPlugIn_->SampleCMPlugIn_HandleSelection( instance: %p, inContext: %p, inCommandID: 0x%08lX )", |
thisInstance, inContext, inCommandID ); |
#endif LOG_ENTRY_POINTS |
OSStatus status = noErr; |
// Sequence the command ids |
gNumCommandIDs = 0; |
// this is a quick sample that looks for text in the context descriptor |
// make sure the descriptor isn't null |
if ( inContext ) { |
AEDesc theAEDesc = { typeNull, NULL }; |
if ( typeAEList == inContext->descriptorType ) |
status = FileSubMenu_Handle( inContext, inCommandID ); |
else if ( typeAlias == inContext->descriptorType ) { |
status = AECoerceDesc( inContext, typeAEList, &theAEDesc ); |
if ( noErr == status ) { |
status = FileSubMenu_Handle( &theAEDesc, inCommandID ); |
AEDisposeDesc( &theAEDesc ); |
} else { |
fprintf( stderr, "\nSampleCMPlugIn_HandleSelection: Unable to coerce to list." ); |
} |
} else { |
// try to get text out of the context descriptor; make sure to coerce it |
// because the app may have passed an object specifier or styled text, etc. |
if ( AECoerceDesc( inContext, typeUTF8Text, &theAEDesc ) == noErr ) { |
++gNumCommandIDs; |
if ( inCommandID == gNumCommandIDs ) { |
Size tSize = AEGetDescDataSize( &theAEDesc ); |
Ptr tPtr = NewPtrClear( tSize ); |
if ( tPtr ) { |
AEGetDescData( &theAEDesc, tPtr, tSize ); |
if ( noErr == status ) { |
printf( "\nSampleCMPlugIn_HandleSelection( command: %ld, text: \"%s\" )", inCommandID, tPtr ); |
} |
DisposePtr( tPtr ); |
} |
} |
AEDisposeDesc( &theAEDesc ); |
} else { |
fprintf( stderr, "\nSampleCMPlugIn_HandleSelection: Unable to coerce to text." ); |
++gNumCommandIDs; |
} |
} |
// handle the SubMenu for our plugin |
SampleSubMenu_Handle( inContext, inCommandID ); |
} else { |
fprintf( stderr, "\nSampleCMPlugIn_HandleSelection: NULL descriptor" ); |
++gNumCommandIDs; |
} |
return noErr; |
} // SampleCMPlugIn_HandleSelection |
// ----------------------------------------------------------------------------- |
// PostMenuCleanup |
// ----------------------------------------------------------------------------- |
// The implementation of the PostMenuCleanup test interface function. |
// |
static void SampleCMPlugIn_PostMenuCleanup( void * thisInstance ) |
{ |
#if LOG_ENTRY_POINTS |
printf( "\nSampleCMPlugIn_PostMenuCleanup( instance: %p )", thisInstance ); |
#endif LOG_ENTRY_POINTS |
if ( gMenuEventHandlerRef ) |
RemoveEventHandler( gMenuEventHandlerRef ); |
if ( gMenuEventHandlerUPP ) |
DisposeEventHandlerUPP( gMenuEventHandlerUPP ); |
} // SampleCMPlugIn_PostMenuCleanup |
// **************************************************** |
#pragma mark - |
#pragma mark * local ( static ) function implementations * |
// ---------------------------------------------------- |
// ----------------------------------------------------------------------------- |
// Copy_CFStringRefToCString |
// ----------------------------------------------------------------------------- |
// Note: If not NULL the results have to be DisposePtr'ed. |
static char * Copy_CFStringRefToCString( CFStringRef pCFStringRef ) |
{ |
char * results = NULL; |
if ( pCFStringRef ) { |
CFIndex length = sizeof( UniChar ) * CFStringGetLength( pCFStringRef ) + 1; |
results = ( char * ) NewPtrClear( length ); |
if ( !CFStringGetCString( pCFStringRef, results, length, kCFStringEncodingASCII ) ) { |
if ( !CFStringGetCString( pCFStringRef, results, length, kCFStringEncodingUTF8 ) ) { |
DisposePtr( results ); |
results = NULL; |
} |
} |
} |
return results; |
} // Copy_CFStringRefToCString |
// ----------------------------------------------------------------------------- |
// SampleCMPlugIn_Alloc |
// ----------------------------------------------------------------------------- |
// Utility function that allocates a new instance. |
// |
static SampleCMPlugIn_ptr SampleCMPlugIn_Alloc( CFUUIDRef inFactoryID ) |
{ |
#if LOG_ENTRY_POINTS |
printf( "SampleCMPlugIn_Alloc( %p )\n", inFactoryID ); |
#endif |
// Allocate memory for the new instance. |
SampleCMPlugIn_ptr theNewInstance; |
theNewInstance = ( SampleCMPlugIn_ptr ) malloc( sizeof( SampleCMPlugIn_rec ) ); |
// Point to the function table |
theNewInstance->cmInterface = &gSampleCMInterface; |
// Retain and keep an open instance refcount for each factory. |
theNewInstance->factoryID = CFRetain( inFactoryID ); |
CFPlugInAddInstanceForFactory( inFactoryID ); |
// This function returns the IUnknown interface |
// so set the refCount to one. |
theNewInstance->refCount = 1; |
return theNewInstance; |
} // SampleCMPlugIn_Alloc |
// ----------------------------------------------------------------------------- |
// SampleCMPlugIn_Dealloc |
// ----------------------------------------------------------------------------- |
// Utility function that deallocates the instance when |
// the refCount goes to zero. |
// |
static void SampleCMPlugIn_Dealloc( SampleCMPlugIn_ptr thisInstance ) |
{ |
#if LOG_ENTRY_POINTS |
printf( "SampleCMPlugIn_Dealloc( %p )\n", thisInstance ); |
#endif LOG_ENTRY_POINTS |
CFUUIDRef theFactoryID = thisInstance->factoryID; |
free( thisInstance ); |
if ( theFactoryID ) { |
CFPlugInRemoveInstanceForFactory( theFactoryID ); |
CFRelease( theFactoryID ); |
} |
} // SampleCMPlugIn_Dealloc |
// ***************************************************** |
// |
// Routine: Command_AddToAEDescList( inCommandCFStringRef, inCommandID, inAttributes, inModifiers, ioCommandList ) |
// |
// Purpose: Create the file sub menu item commnds |
// |
// Inputs: inCommandCFStringRef - the text for the command |
// inCommandID - its command ID |
// inAttributes - its attributes |
// inModifiers - its modifiers |
// ioCommandList - AEDescList of commands to append |
// |
// Returns: OSStatus - error code |
// |
static OSStatus Command_AddToAEDescList( CFStringRef inCommandCFStringRef, SInt32 inCommandID, MenuItemAttributes inAttributes, UInt32 inModifiers, AEDescList* ioCommandList ) |
{ |
OSStatus result = noErr; |
AERecord theCommandRecord = { typeNull, NULL }; |
CFStringRef tCFStringRef = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR( "%@-[0x%08lX]" ), inCommandCFStringRef, inCommandID ); |
#if LOG_ENTRY_POINTS |
if ( tCFStringRef ) { |
char buffer[256]; |
if ( CFStringGetCString( tCFStringRef, buffer, sizeof( buffer ), kCFStringEncodingUTF8) ) { |
printf( "\nSampleCMPlugIn->Command_AddToAEDescList( \"%s\", 0x%08lX, 0x%08lX, 0x%08lX, %p );", buffer, inCommandID, inAttributes, inModifiers, ioCommandList ); |
} |
CFShow( tCFStringRef ); |
} |
#endif LOG_ENTRY_POINTS |
// create an AEDesc list for our command |
result = AECreateList( NULL, 0, TRUE, &theCommandRecord ); |
require_noerr( result, Command_AddToAEDescList_fail ); |
// stick the command text into the aerecord |
CFRetain( tCFStringRef ); |
result = AEPutKeyPtr( &theCommandRecord, keyContextualMenuName, typeCFStringRef, &tCFStringRef, sizeof( CFStringRef ) ); |
require_noerr( result, Command_AddToAEDescList_fail ); |
// stick the command ID into the AERecord |
result = AEPutKeyPtr( &theCommandRecord, keyContextualMenuCommandID, typeSInt32, &inCommandID, sizeof( inCommandID ) ); |
require_noerr( result, Command_AddToAEDescList_fail ); |
if ( gHasAttributeAndModifierKeys ) { |
// stick the attributes into the AERecord |
if ( inAttributes != 0 ) { |
result = AEPutKeyPtr( &theCommandRecord, keyContextualMenuAttributes, typeSInt32, &inAttributes, sizeof( inAttributes ) ); |
require_noerr( result, Command_AddToAEDescList_fail ); |
} |
// stick the modifiers into the AERecord |
if ( inModifiers != 0 ) { |
result = AEPutKeyPtr( &theCommandRecord, keyContextualMenuModifiers, typeSInt32, &inModifiers, sizeof( inModifiers ) ); |
require_noerr( result, Command_AddToAEDescList_fail ); |
} |
} |
#if FALSE // Set this TRUE to printf the command record |
Handle strHdl; |
result = AEPrintDescToHandle( &theCommandRecord, &strHdl ); |
if ( noErr == result ) { |
char nul = '\0'; |
PtrAndHand( &nul, strHdl, 1 ); |
printf( "\nSampleCMPlugIn->Command_AddToAEDescList: theCommandRecord:\"%s\".", *strHdl ); |
fflush( stdout ); |
DisposeHandle( strHdl ); |
} |
#endif |
// stick this record into the list of commands that we are |
// passing back to the CMM |
result = AEPutDesc( ioCommandList, 0, &theCommandRecord ); |
Command_AddToAEDescList_fail: ; |
// clean up after ourself; dispose of the AERecord |
AEDisposeDesc( &theCommandRecord ); |
if ( tCFStringRef ) { |
CFRelease( tCFStringRef ); |
} |
return result; |
} // Command_AddToAEDescList |
/***************************************************** |
* |
* Routine: FileSubMenu_Create( ioCommandList ) |
* |
* Purpose: Create the file sub menu item commnds |
* |
* Inputs: ioCommandList - AEDescList of commands to which we append our file sub menu commands |
* |
* Returns: OSStatus - error code |
*/ |
static OSStatus FileSubMenu_Create( const AEDesc * inContext, AEDescList * ioCommandList ) |
{ |
OSStatus result = noErr; |
AEDescList theSubMenuCommands = { typeNull, NULL }; |
AERecord theSubMenuCommand = { typeNull, NULL }; |
Str255 theSubMenuCommandText = "\pSubMenu Here"; |
// the first thing we should do is create an AEDescList of subcommands |
// set up the AEDescList |
result = AECreateList( NULL, 0, FALSE, &theSubMenuCommands ); |
require_noerr( result, FileSubMenu_Create_Complete_fail ); |
long idx, numItems; |
result = AECountItems( inContext, &numItems ); |
if ( noErr == result ) { |
sprintf( ( char * ) &theSubMenuCommandText[1], "%ld item(s)!", numItems ); |
theSubMenuCommandText[0] = strlen( ( char * ) &theSubMenuCommandText[1] ); |
for ( idx = 1; idx <= numItems; idx++ ) { |
AEKeyword theAEKeyword; |
AEDesc theAEDesc; |
result = AEGetNthDesc( inContext, idx, typeAlias, &theAEKeyword, &theAEDesc ); |
if ( noErr != result ) continue; |
if ( typeAlias == theAEDesc.descriptorType ) { |
FSRef tFSRef; |
Size dataSize = AEGetDescDataSize( &theAEDesc ); |
AliasHandle tAliasHdl = ( AliasHandle ) NewHandle( dataSize ); |
if ( tAliasHdl ) { |
Boolean wasChanged; |
result = AEGetDescData( &theAEDesc, *tAliasHdl, dataSize ); |
if ( noErr == result ) { |
result = FSResolveAlias( NULL, tAliasHdl, &tFSRef, &wasChanged ); |
if ( noErr == result ) { |
CFURLRef tCFURLRef = CFURLCreateFromFSRef( kCFAllocatorDefault, &tFSRef ); |
CFStringRef nameCFStringRef = CFURLCopyLastPathComponent( tCFURLRef ); |
CFRelease( tCFURLRef ); // don't need this anymore |
Command_AddToAEDescList( nameCFStringRef, 0x00010000 + idx, 0, kMenuNoModifiers, &theSubMenuCommands ); |
CFRelease( nameCFStringRef ); // don't need this anymore |
} |
} |
DisposeHandle( ( Handle ) tAliasHdl ); |
} |
} |
AEDisposeDesc( &theAEDesc ); |
} |
} |
// 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 Command_AddToAEDescList 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 |
result = AECreateList( NULL, 0, TRUE, &theSubMenuCommand ); |
require_noerr( result, FileSubMenu_Create_fail ); |
// stick the command text into the aerecord |
result = AEPutKeyPtr( &theSubMenuCommand, keyContextualMenuName, typeUTF8Text, &theSubMenuCommandText[1], theSubMenuCommandText[0] ); |
require_noerr( result, FileSubMenu_Create_fail ); |
// stick the subcommands into into the AERecord |
result = AEPutKeyDesc( &theSubMenuCommand, keyContextualMenuSubmenu, &theSubMenuCommands ); |
require_noerr( result, FileSubMenu_Create_fail ); |
// stick the supercommand into the list of commands that we are |
// passing back to the CMM |
result = AEPutDesc( ioCommandList, // the list we're putting our command into |
0, // stick this command onto the end of our list |
&theSubMenuCommand ); // the command I'm putting into the list |
// clean up after ourself |
FileSubMenu_Create_fail: ; |
AEDisposeDesc( &theSubMenuCommands ); |
AEDisposeDesc( &theSubMenuCommand ); |
FileSubMenu_Create_Complete_fail: |
return result; |
} // FileSubMenu_Create |
//***************************************************** |
// |
// Routine: FileSubMenu_Handle( inContext, inCommandID ) |
// |
// Purpose: This is where I handle the file sub menu item commnds |
// |
// Inputs: inContext - EventHandlerCallRef ( not being used ) |
// inCommandID - EventRef |
// |
// Returns: OSStatus - error code |
// |
static OSStatus FileSubMenu_Handle( const AEDesc * inContext, SInt32 inCommandID ) |
{ |
long idx, numItems; |
OSStatus result = noErr; |
if ( ( inCommandID >> 16 ) != 0x0001 ) |
return result; |
#if LOG_ENTRY_POINTS |
printf( "\nSampleCMPlugIn->FileSubMenu_Handle( inContext: %p, inCommandID: 0x%08lX )", inContext, inCommandID ); |
#endif LOG_ENTRY_POINTS |
result = AECountItems( inContext, &numItems ); |
if ( noErr == result ) { |
for ( idx = 1; idx <= numItems; idx++ ) { |
AEKeyword theAEKeyword; |
AEDesc theAEDesc; |
result = AEGetNthDesc( inContext, idx, typeAlias, &theAEKeyword, &theAEDesc ); |
if ( noErr != result ) continue; |
if ( typeAlias == theAEDesc.descriptorType ) { |
FSRef tFSRef; |
Size dataSize = AEGetDescDataSize( &theAEDesc ); |
AliasHandle tAliasHdl = ( AliasHandle ) NewHandle( dataSize ); |
if ( tAliasHdl ) { |
Boolean wasChanged; |
result = AEGetDescData( &theAEDesc, *tAliasHdl, dataSize ); |
if ( noErr == result ) { |
result = FSResolveAlias( NULL, tAliasHdl, &tFSRef, &wasChanged ); |
if ( noErr == result ) { |
CFURLRef tCFURLRef = CFURLCreateFromFSRef( kCFAllocatorDefault, &tFSRef ); |
CFStringRef nameCFStringRef = CFURLCopyLastPathComponent( tCFURLRef ); |
CFRelease( tCFURLRef ); // don't need this anymore |
if ( nameCFStringRef ) { |
if ( inCommandID == ( 0x00010000 + idx ) ) { |
char * tPtr = Copy_CFStringRefToCString( nameCFStringRef ); |
if ( tPtr ) { |
printf( "\nSampleCMPlugIn->FileSubMenu_Handle( file: \"%s\" )", tPtr ); |
DisposePtr( tPtr ); |
} |
} |
CFRelease( nameCFStringRef ); // don't need this anymore |
} |
} |
} |
DisposeHandle( ( Handle ) tAliasHdl ); |
} |
} |
AEDisposeDesc( &theAEDesc ); |
} |
} |
return result; |
} // FileSubMenu_Handle |
//***************************************************** |
// |
// Routine: SampleSubMenu_Create( ioCommandList ) |
// |
// Purpose: Create some sub menu item commnds |
// |
// Inputs: ioCommandList - AEDescList of commands to which we append our sub menu commands |
// |
// Returns: OSStatus - error code |
// |
static OSStatus SampleSubMenu_Create( AEDescList * ioCommandList ) |
{ |
OSStatus result = noErr; |
AEDescList theSubMenuCommands = { typeNull, NULL }; |
AERecord theSubMenuCommand = { typeNull, NULL }; |
Str255 theSubMenuCommandText = "\pSubMenu Here"; |
Str255 theSubMenuCommandPlusText = "\pSubMenu Here-[0x20000]"; |
long commandID = 0x00020000; |
#if LOG_ENTRY_POINTS |
printf( "\nSampleCMPlugIn->SampleSubMenu_Create( )." ); |
#endif LOG_ENTRY_POINTS |
// the first thing we should do is create an AEDescList of subcommands |
// set up the AEDescList |
result = AECreateList( NULL, 0, FALSE, &theSubMenuCommands ); |
require_noerr( result, SampleSubMenu_Create_Complete_fail ); |
int idx, count = sizeof( gSubCommandCStrings ) / sizeof( char * ); |
for ( idx = 0; idx < count; idx++ ) { |
CFStringRef itemNameCFStringRef = CFStringCreateWithCString( kCFAllocatorDefault, gSubCommandCStrings[idx], kCFStringEncodingUTF8 ); |
if ( itemNameCFStringRef ) { |
result = Command_AddToAEDescList( itemNameCFStringRef, 0x00020001 + idx, 0, kMenuNoModifiers, &theSubMenuCommands ); |
require_noerr( result, SampleSubMenu_Create_CreateDesc_fail ); |
CFRelease( itemNameCFStringRef ); |
} |
} |
// 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 Command_AddToAEDescList 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 |
result = AECreateList( NULL, 0, TRUE, &theSubMenuCommand ); |
require_noerr( result, SampleSubMenu_Create_fail ); |
// stick the command text into the aerecord |
if ( gHasAttributeAndModifierKeys ) { |
result = AEPutKeyPtr( &theSubMenuCommand, keyContextualMenuName, typeUTF8Text, &theSubMenuCommandPlusText[1], theSubMenuCommandPlusText[0] ); |
require_noerr( result, SampleSubMenu_Create_fail ); |
// stick the command ID into the AERecord |
result = AEPutKeyPtr( &theSubMenuCommand, keyContextualMenuCommandID, typeSInt32, &commandID, sizeof( commandID ) ); |
require_noerr( result, SampleSubMenu_Create_fail ); |
if ( gHasAttributeAndModifierKeys ) { |
const MenuItemAttributes tMenuItemAttributes = kMenuItemAttrSubmenuParentChoosable; |
result = AEPutKeyPtr( &theSubMenuCommand, keyContextualMenuAttributes, typeSInt32, &tMenuItemAttributes, sizeof( tMenuItemAttributes ) ); |
require_noerr( result, SampleSubMenu_Create_fail ); |
} |
} else { |
result = AEPutKeyPtr( &theSubMenuCommand, keyContextualMenuName, typeUTF8Text, &theSubMenuCommandText[1], theSubMenuCommandText[0] ); |
require_noerr( result, SampleSubMenu_Create_fail ); |
} |
// stick the subcommands into into the AERecord |
result = AEPutKeyDesc( &theSubMenuCommand, keyContextualMenuSubmenu, &theSubMenuCommands ); |
require_noerr( result, SampleSubMenu_Create_fail ); |
// stick the supercommand into the list of commands that we are passing back to the CMM |
result = AEPutDesc( ioCommandList, // the list we're putting our command into |
0, // stick this command onto the end of our list |
&theSubMenuCommand ); // the command I'm putting into the list |
// clean up after ourself |
SampleSubMenu_Create_fail: ; |
AEDisposeDesc( &theSubMenuCommands ); |
SampleSubMenu_Create_CreateDesc_fail: ; |
AEDisposeDesc( &theSubMenuCommand ); |
SampleSubMenu_Create_Complete_fail: ; |
return result; |
} // SampleSubMenu_Create |
// ***************************************************** |
// |
// Routine: SampleSubMenu_Handle( inContext, inCommandID ) |
// |
// Purpose: This is where I handle the sub menu item commnds |
// |
// Inputs: inContext - EventHandlerCallRef ( not being used ) |
// inCommandID - EventRef |
// |
// Returns: OSStatus - error code |
// |
static OSStatus SampleSubMenu_Handle( const AEDesc * inContext, SInt32 inCommandID ) |
{ |
OSStatus result = noErr; |
#pragma unused ( inContext ) |
switch ( inCommandID ) { |
case 0x00020001: { |
printf( "\n\"First Subcommand\"" ); |
break; |
} |
case 0x00020002: { |
printf( "\n\"Second Subcommand\"" ); |
break; |
} |
case 0x00020003: { |
printf( "\n\"Third Subcommand\"" ); |
break; |
} |
case 0x00020004: { |
printf( "\n\"Fourth Subcommand\"" ); |
break; |
} |
default: { |
if ( 0x0002 == ( inCommandID >> 16 )) { |
printf( "\nSampleSubMenu_Handle:( inCommandID: %.8lX )", inCommandID ); |
} |
break; |
} |
} |
return result; |
} // SampleSubMenu_Handle |
/***************************************************** |
* |
* Routine: MenuEvent_Handle( inEventHandlerCallRef, inEventRef, inUserData ) |
* |
* Purpose: I'm using this as a hook to modify menu items before the finder CMM code displays them |
* In this case I'm trying to add an Icon |
* |
* Inputs: inEventHandlerCallRef - EventHandlerCallRef ( not being used ) |
* inEventRef - EventRef |
* inUserData - pointer to users data ( not being used ) |
* |
* Returns: OSStatus - Always eventNotHandledErr since this is just a hook; we don't handle any events here |
*/ |
static pascal OSStatus MenuEvent_Handle( EventHandlerCallRef inEventHandlerCallRef, EventRef inEventRef, void * inUserData ) |
{ |
OSStatus result = eventNotHandledErr; // assume that we're not going to handle the event ( which is ALWAYS TRUE ) |
EventClass theClass = GetEventClass( inEventRef ); |
EventClass theKind = GetEventKind( inEventRef ); |
#if LOG_ENTRY_POINTS |
printf( "\nMenuEvent_Handle!" ); fflush( stdout ); |
#endif LOG_ENTRY_POINTS |
OSStatus status = noErr; |
CFBundleRef myCFBundleRef = CFBundleGetBundleWithIdentifier( kMyBundleIdentifier ); |
CFURLRef tCFURLRef = CFBundleCopyResourceURL( myCFBundleRef, CFSTR( "Skull&Bones" ), CFSTR( "icns" ), NULL ); |
IconRef iconRef = NULL; |
if ( tCFURLRef ) { |
FSRef tFSRef; |
status = ( CFURLGetFSRef( tCFURLRef, &tFSRef ) ? noErr : fnfErr ); |
if ( noErr == status ) { |
status = RegisterIconRefFromFSRef( 'CMMs', 'skul', &tFSRef, &iconRef ); |
if ( noErr != status ) |
fprintf( stderr, "\nSampleCMPlugIn->MenuEvent_Handle->RegisterIconRefFromFSRef error: %ld ( 0x%08lX ).", status, status ); |
} else { |
fprintf( stderr, "\nSampleCMPlugIn->MenuEvent_Handle->CFURLGetFSRef error: %ld ( 0x%08lX ).", status, status ); |
} |
CFRelease( tCFURLRef ); |
} else { |
fprintf( stderr, "\nSampleCMPlugIn->MenuEvent_Handle->CFBundleCopyResourceURL is NULL." ); |
} |
fflush( stderr ); |
switch ( theClass ) { |
case kEventClassMenu: { |
switch ( theKind ) { |
case kEventMenuPopulate: { |
status = CallNextEventHandler( inEventHandlerCallRef, inEventRef ); |
MenuRef myMenuRef; |
status = GetEventParameter( inEventRef, kEventParamDirectObject, typeMenuRef, NULL, sizeof( MenuRef ), NULL, &myMenuRef ); |
Boolean firstOpen; |
status = GetEventParameter( inEventRef, kEventParamMenuFirstOpen, typeBoolean, NULL, sizeof( Boolean ), NULL, &firstOpen ); |
UInt32 menuContext; |
status = GetEventParameter( inEventRef, kEventParamMenuContext, typeUInt32, NULL, sizeof( UInt32 ), NULL, &menuContext ); |
#if LOG_ENTRY_POINTS |
printf( "\nSampleCMPlugIn->MenuEvent_Handle: {ref: %8.8lX, first: %s, context: %8.8lX}.", |
( UInt32 ) myMenuRef, firstOpen ? "Yes" : "No", menuContext ); |
CFStringRef menuCFStringRef; |
status = CopyMenuTitleAsCFString( myMenuRef, &menuCFStringRef ); |
if ( ( noErr == status ) && ( menuCFStringRef ) ) { |
char * myPtr = Copy_CFStringRefToCString( menuCFStringRef ); |
if ( myPtr ) { |
if ( strlen( myPtr ) ) { |
printf( "\nSampleCMPlugIn->MenuEvent_Handle->CopyMenuTitleAsCFString: \"%s\".", myPtr ); |
} |
DisposePtr( myPtr ); |
} |
CFRelease( menuCFStringRef ); |
} |
#endif LOG_ENTRY_POINTS |
// |
// Try to match against the menu item text strings. |
// |
short idx, count = CountMenuItems( myMenuRef ); |
for ( idx = 1;idx <= count;idx++ ) { |
char itemString[256]; |
CFStringRef tCFStringRef; |
status = CopyMenuItemTextAsCFString( myMenuRef, idx, &tCFStringRef ); |
if ( noErr != status ) { |
continue; |
} |
if ( !CFStringGetCString( tCFStringRef, itemString, sizeof( itemString ), kCFStringEncodingUTF8 ) ) { |
continue; |
} |
// Ok, here's our first string... |
if ( 0 == strncmp( gSubCommandCStrings[0], itemString, strlen( gSubCommandCStrings[0] ) ) ) { |
printf( "\nSampleCMPlugIn->MenuEvent_Handle: found first sub item!" ); |
// |
// Try SetItemMark with this one... |
// |
SetItemMark( myMenuRef, idx, kMenuPencilGlyph ); |
// |
// ...this works! |
// |
} else if ( 0 == strncmp( gSubCommandCStrings[1], itemString, strlen( gSubCommandCStrings[1] ) ) ) { |
printf( "\nSampleCMPlugIn->MenuEvent_Handle: found second sub item!" ); |
// |
// Try to use SetMenuItemIconHandle with kMenuIconResourceType |
// to pass a CFStringRef naming a resource in the main bundle of the process |
// |
CFStringRef tIconCFStringRef = CFSTR( "Skull&Bones.icns" ); |
status = SetMenuItemIconHandle( myMenuRef, idx, kMenuIconResourceType, ( Handle ) tIconCFStringRef ); |
if ( noErr != status ) { |
fprintf( stderr, "\nSampleCMPlugIn->MenuEvent_Handle->SetMenuItemIconHandle( #%d ) error: %ld ( 0x%08lX ).", idx, status, status ); |
} |
// |
// This doesn't work. Note that there's a space for the icon but it's blank. weird. |
// Just guessing but it's probably because the finder doesn't have this icon file. |
// it's looking in the "main bundle" ( the Finder ) not the CMM bundle for this file? |
// |
} |
else if ( 0 == strncmp( gSubCommandCStrings[2], itemString, strlen( gSubCommandCStrings[2] ) ) ) { |
printf( "\nSampleCMPlugIn->MenuEvent_Handle: found third sub item!" ); |
// |
// This time we're going to try to use SetMenuItemIconHandle with kMenuIconRefType to pass an icon ref |
// |
if ( myMenuRef ) { |
status = SetMenuItemIconHandle( myMenuRef, idx, kMenuIconRefType, ( Handle ) iconRef ); |
if ( noErr != status ) |
fprintf( stderr, "\nSampleCMPlugIn->MenuEvent_Handle->SetMenuItemIconHandle( #%d ) error: %ld ( 0x%08lX ).", idx, status, status ); |
else |
printf( "\nSampleCMPlugIn->MenuEvent_Handle->SetMenuItemIconHandle( #%d ) success!", idx ); |
} |
// |
// This works! |
// |
} |
else if ( 0 == strncmp( gSubCommandCStrings[3], itemString, strlen( gSubCommandCStrings[3] ) ) ) { |
printf( "\nSampleCMPlugIn->MenuEvent_Handle: found fourth sub item!" ); |
// |
// this is the same code as above, I just want to test DisableMenuItemIcon |
// |
if ( myMenuRef ) { |
status = SetMenuItemIconHandle( myMenuRef, idx, kMenuIconRefType, ( Handle ) iconRef ); |
if ( noErr != status ) |
fprintf( stderr, "\nSampleCMPlugIn->MenuEvent_Handle->SetMenuItemIconHandle( #%d ) error: %ld ( 0x%08lX ).", idx, status, status ); |
else |
printf( "\nSampleCMPlugIn->MenuEvent_Handle->SetMenuItemIconHandle( #%d ) success!", idx ); |
} |
DisableMenuItemIcon( myMenuRef, idx ); |
// |
// This works! |
// |
} |
} |
break; |
} |
default: |
fprintf( stderr, "\nSampleCMPlugIn->MenuEvent_Handle: handled event class ( \"%.4s\" ) & unhandled kind ( \"%.4s\" ).", ( char * ) &theClass, ( char * ) &theKind ); |
break; |
} |
break; |
} |
default: |
fprintf( stderr, "\nSampleCMPlugIn->MenuEvent_Handle: Unhandled event class ( \"%.4s\" ) & kind ( \"%.4s\" ).", ( char * ) &theClass, ( char * ) &theKind ); |
break; |
} |
return result; |
} // MenuEvent_Handle |
Copyright © 2006 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2006-10-09