Important: The information in this document is obsolete and should not be used for new development.
Factoring the Quit Command and the New Command
This section demonstrates how to factor two File menu commands: Quit and New.When the user chooses a menu command, an application first determines which one was chosen and then performs the action associated with that command. For example, when a user chooses Quit from the File menu, an application that is not factored simply calls an application-defined
DoQuitroutine. Because Quit Application is one of the required Apple events, it is relatively easy for most applications that support Apple events to factor the code that responds to the Quit command.After a factored application has determined that the user has chosen the Quit command, it sends the Quit Application event to itself by calling its
MyDoMenuQuitroutine.
PROCEDURE MyDoMenuQuit; VAR myErr: OSErr; BEGIN myErr := MySendAEQuit(kAEAskUser); {handle any errors} END;TheMyDoMenuQuitroutine in turn calls theMySendAEQuitroutine shown in
Listing 9-1, which creates the Quit Application event and sends it.Listing 9-1 A function used by a factored application to send itself a Quit Application event
FUNCTION MySendAEQuit (saveOpt: DescType): OSErr; VAR myAppleEvent, defReply: AppleEvent; myErr, ignoreErr: OSErr; BEGIN {create Quit event} myErr := AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, gSelfAddrDesc, kAutoGenerateReturnID, kAnyTransactionID, myAppleEvent); IF myErr = noErr THEN {add optional parameter that specifies whether this app } { should prompt user if window is dirty} myErr := AEPutParamPtr(myAppleEvent, keyAESaveOptions, typeEnumerated, @saveOpt, SizeOf(saveOpt)); IF myErr = noErr THEN {send event} myErr := AESend(myAppleEvent, defReply, kAENoReply+kAEAlwaysInteract, kAENormalPriority, kAEDefaultTimeOut, NIL, NIL); MySendAEQuit := myErr; ignoreErr := AEDisposeDesc(myAppleEvent); END;The input to theMySendAEQuitroutine is a constant that indicates whether to save dirty windows without asking the user (kAEYes), quit without saving dirty windows (kAENo), or ask the user whether each dirty window should be saved (kAEAskUser). In this example, the constantkAEAskUserpassed to theMySendAEQuitroutine indicates that the user will be asked whether each dirty window should be saved.After the application receives the Quit Application event, the
MyHandleQuithandler shown in Listing 9-2 performs all the actions associated with that event, such as saving any open documents. (Note that your application should call theExitToShellprocedure from the main event loop, not from your handler for the Quit Application event.)Listing 9-2 A routine used by a factored application to handle a Quit Application event
FUNCTION MyHandleQuit (theAppleEvent, reply: AppleEvent; handlerRefcon: LongInt): OSErr; VAR userCanceled: Boolean; saveOpt, returnedType: DescType; actSize: Size; myErr: OSErr; BEGIN {check for missing required parameters} myErr := MyGotRequiredParams(theAppleEvent); IF myErr = noErr THEN BEGIN {pick up optional save parameter} saveOpt := kAEAskUser; {the default} myErr := AEGetParamPtr(theAppleEvent, keyAESaveOptions, typeEnumerated, returnedType, @saveOpt, SizeOf(saveOpt), actSize); IF myErr = errAEDescNotFound THEN myErr := noErr; MyHandleQuit := myErr; IF myErr = noErr THEN BEGIN userCanceled := MyPrepareToTerminate(saveOpt); IF userCanceled THEN MyHandleQuit := kUserCanceled; END; END ELSE MyHandleQuit := myErr; END;The handler in Listing 9-2 calls another function supplied by the application, theMyPrepareToTerminatefunction. When the value of the optional parameter that specifies how to deal with dirty windows equalskAEAskUser, this function asks the user whether to save each dirty window and returns a Boolean value that indicates whether the user canceled the Quit request. It also responds appropriately to the other possible values of the optional parameter.If recording has been turned on for a scripting component (for example, after a user clicks the Record button in the Script Editor application) and the user quits the application, the Apple Event Manager automatically sends the scripting component a copy of the Quit Application event sent by the
MySendAEQuitroutine. The scripting component records the event in a compiled script. When a user executes the recorded script, the scripting component sends the same Quit Application event to the application, which calls theMyHandleQuitfunction and responds to the event just as if the user had chosen Quit from the File menu.After you have factored the commands associated with required Apple events for an existing application, you can move on to the other commands in the File menu, such as New. After a factored application has determined that the user has chosen New, it calls its
MyDoMenuNewroutine, which sends the Create Element event to the application.
PROCEDURE MyDoMenuNew; VAR myErr := OSErr; BEGIN myErr := MySendAECreateElement(gNullDesc, cDocument); {handle any errors} END;The container for the new element is the application's default container, specified by a null descriptor record, and the desired class iscDocument. TheMyDoMenuNewroutine in turn calls theMySendAECreateElementroutine shown in Listing 9-3, which creates the Apple event and sends it.Listing 9-3 A routine used by a factored application to send itself a Create Element event
FUNCTION MySendAECreateElement (cont: AEDesc; elemClass: DescType): OSErr; VAR myAppleEvent, defReply: AppleEvent; myErr, ignoreErr: OSErr; BEGIN {create Create Element event} myErr := AECreateAppleEvent(kCoreEventClass, kAECreateElement, gSelfAddrDesc, kAutoGenerateReturnID, kAnyTransactionID, myAppleEvent); IF myErr = noErr THEN {add parameter that specifies insertion location for the } { new element} myErr := AEPutParamDesc(myAppleEvent,keyAEInsertHere,cont); IF myErr = noErr THEN {add parameter that specifies new element's object class} myErr := AEPutParamPtr(myAppleEvent, keyAEObjectClass, typeType, @elemClass, SizeOf(elemClass)); IF myErr = noErr THEN {send the event} myErr := AESend(myAppleEvent, defReply, kAENoReply+kAECanInteract, kAENormalPriority, kAEDefaultTimeOut, NIL, NIL); MySendAECreateElement := myErr; ignoreErr := AEDisposeDesc(myAppleEvent); {must dispose of } { event} END;For the purposes of this example, the routine shown in Listing 9-3 sends only the required parameters and can only create a new active window with the default name. After the application receives the Create Element event, itsMyHandleCreateElementhandler performs the requested action, as shown in Listing 9-4. In this case, it creates a new active window with a default title.Listing 9-4 The Create Element event handler for a factored application
FUNCTION MyHandleCreateElement (theAppleEvent: AppleEvent; reply: AppleEvent; handlerRefCon: LongInt): OSErr; VAR myCont: AEDesc; returnedType, newElemClass: DescType; actSize: Size; contClass: DescType; window: WindowPtr; myErr: OSErr; BEGIN {get the parameters out of the event} {first get the direct parameter, which specifies insertion } { location for new window--that is, frontmost window} myCont.dataHandle := NIL; myErr := AEGetParamDesc(theAppleEvent, keyAEInsertHere, typeWildCard, myCont); IF myErr = noErr THEN {get the other required parameter, which specifies class } { cDocument when MyHandleCreateElement creates a new window} myErr := AEGetParamPtr(theAppleEvent, keyAEObjectClass, typeType, returnedType, @newElemClass, SizeOf(newElemClass), actSize); IF myErr = noErr THEN myErr := MyGotRequiredParams(theAppleEvent); MyHandleCreateElement := myErr; IF myErr = noErr THEN BEGIN {check container and class, just to make sure} IF (myCont.descriptorType <> typeNull) OR (newElemClass <> cDocument) THEN MyHandleCreateElement := kWrongContainerOrElement ELSE {MyNewWindow creates a new window with a default name } { and returns a pointer to it in the window parameter} MyHandleCreateElement := MyNewWindow(window); END; myErr := AEDisposeDesc(myCont); {if your app sends a reply in response to the Create Element } { event, then set up the reply event as appropriate} END;If recording has been turned on for a scripting component (for example, after a user clicks the Record button in the Script Editor application), the Apple Event Manager automatically sends the scripting component a copy of the Create Element event sent by theMySendAECreateElementroutine. The scripting component records the Apple event as a statement in a compiled script. When a user executes the recorded script, the scripting component sends the same Create Element event to the application, which calls itsMyHandleCreateElementhandler and responds to the event just as if the user had chosen New from the File menu.