Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Interapplication Communication /
Chapter 9 - Recording Apple Events / Factoring Your Application for Recording


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 DoQuit routine. 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 MyDoMenuQuit routine.

PROCEDURE MyDoMenuQuit;
VAR
   myErr: OSErr;
BEGIN
   myErr := MySendAEQuit(kAEAskUser);
   {handle any errors}
END;
The MyDoMenuQuit routine in turn calls the MySendAEQuit routine 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 the MySendAEQuit routine 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 constant kAEAskUser passed to the MySendAEQuit routine indicates that the user will be asked whether each dirty window should be saved.

After the application receives the Quit Application event, the MyHandleQuit handler 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 the ExitToShell procedure 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, the MyPrepareToTerminate function. When the value of the optional parameter that specifies how to deal with dirty windows equals kAEAskUser, 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 MySendAEQuit routine. 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 the MyHandleQuit function 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 MyDoMenuNew routine, 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 is cDocument. The MyDoMenuNew routine in turn calls the MySendAECreateElement routine 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, its MyHandleCreateElement handler 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 the MySendAECreateElement routine. 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 its MyHandleCreateElement handler and responds to the event just as if the user had chosen New from the File menu.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
7 JUL 1996