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: Programmer's Guide to MacApp / Part 1 - MacApp Theory and Architecture
Chapter 6 - Scripting


Dispatching Apple Events

An application may receive Apple events from itself, from another application, from the operating system, or from a script. MacApp uses a global Apple event dispatcher object to send Apple events to the objects specified by the events. The Apple event dispatcher object works together with callbacks from the Apple Event Manager and its OSL component to dispatch Apple events. If you have built your application with MacApp's support for attached scripts, dispatching is a two-stage process:

If you have built your application without MacApp's support for attached scripts, MacApp skips the predispatch step. Appendix A describes how to use the -Attachable option to include MacApp's attachability code when building your application with the MABuild system.

Any object that needs to respond to Apple events mixes in the multiple inheritance class MScriptableObject. Many MacApp classes, including TApplication, TDocument, TWindow, and TFile, already mix in MScriptableObject, so you don't need to mix it in again for any class that descends from one of these classes.

Classes that support scripting generally override methods of MScriptableObject to support a hierarchy of contained objects, to handle specific Apple events, and to get and set object properties. For example, the IconEdit sample application supports setting the color of an icon with an Apple event, so the TIconDocument class overrides the GetObjectProperty and SetObjectProperty methods to respond when the specified property is pColor.

Initializing Scripting

MacApp initialization is described in detail in Chapter 4, "Launching and Terminating an Application." During initialization of the application, the IApplication method calls the InitUScripting routine to initialize the UScripting unit.

MacApp's global InitUScripting routine calls the InitUScripting method of the TOSADispatcher class. That method terminates applications that are not aware of high-level events. Otherwise, InitUScripting calls the Apple Event Manager routine AEObjectInit to initialize the OSL. If a global Apple event dispatcher object has not already been created, InitUScripting creates one, stores a reference to it in TOSADispatcher::fgDispatcher (a global static field), and calls the IOSADispatcher initialization method.

The IOSADispatcher method does some standard initialization tasks, then calls two of its own methods to install various Apple -event- handler routines and other callback routines:

this->InstallDispatchHandlers();
this->InstallObjectCallbacks();
It is also possible to initialize MacApp's scripting support to use a custom subclass of TOSADispatcher. For details, see "Recipe--Installing a Custom Subclass of TOSADispatcher," beginning on page 371.

InstallDispatchHandlers

The InstallDispatchHandlers method looks for any application resources of type 'aedt' (Apple event dispatch table). An 'aedt' resource is an array of entries, each of which maps an Apple event class and ID pair to a MacApp command-number constant. For example, MacApp defines an 'aedt' resource for the four Finder Apple events that all applications are required to support:

resource 'aedt' (kAEDispatchTable) 
{
{
'aevt', 'ansr', cAppleEventReply;
'aevt', 'oapp', cFinderNew;
'aevt', 'odoc', cFinderOpen;
'aevt', 'pdoc', cFinderPrint;
'aevt', 'quit', cFinderQuit;
}
};

This resource also defines the cAppleEventReply command number, used to identify asynchronous replies.

For each entry in each 'aedt' resource, InstallEventDispatchTables calls the Apple Event Manager routine AEInstallEventHandler, passing a universal procedure pointer that specifies the DispatchHandlerGlue method as the event handler to call when an Apple event with the specified class and ID information is received. As a result, all Apple events handled by the application are dispatched to the same method. However, before an Apple event is dispatched to the DispatchHandlerGlue method, it is first predispatched to a different callback routine, described in "InstallPreDispatchHandler" below.

InstallObjectCallbacks

The InstallObjectCallbacks method calls the Apple Event Manager routine AEInstallObjectAccessor. InstallObjectCallbacks passes a universal procedure pointer that specifies the ObjectAccessorGlue method as the object-accessor routine the Apple Event Manager's AEResolve routine should call when resolving an Apple event object specifier. Although it is possible to install multiple object-accessor routines, MacApp uses just this one.

The InstallObjectCallbacks method also calls the Apple Event Manager routine AESetObjectCallbacks, passing universal procedure pointers that specify TOSADispatcher methods as callback routines for

Each of these "glue" methods sets up a failure handler, then calls a similarly named method of the TOSADispatcher class. For example, CompareObjectsGlue calls CompareObjects and AdjustMarksGlue calls AdjustMarks. These callback glue methods may also be called by the OSL's AEResolve routine when resolving an Apple event object specifier.

InstallPreDispatchHandler

If you build your application to include MacApp's attachability code, the first time you call a method such as MScriptableObject:ReadOSAScript or MScriptableObject::SetOSAScript, the InstallPreDispatchHandler method is called. InstallPreDispatchHandler calls the Apple Event Manager routine AEInstallSpecialHandler, passing a universal procedure pointer that specifies the PreDispatchHandlerGlue method as the event handler to call when predispatching Apple events. MacApp uses this routine to predispatch Apple events to objects with attached scripts.

The global TOSADispatcher object keeps a reference to the number of attached scripts in the application. If that number goes to 0, the predispatch handler is uninstalled.

Apple Event Dispatching

Once MacApp's UScripting unit has been initialized, the application is ready to dispatch any Apple event it knows how to handle. Apple events are dispatched in one of two ways:

Predispatching Apple Events to Attached Scripts

The PreDispatchHandlerGlue method first calls its GetAppleEventCommandNumber method, which calls the Apple Event Manager routine AEGetEventHandler to get a MacApp command number to associate with the event. Command number information is available from a table set up by the InstallDispatchHandlers method, based on the application's 'aedt' resources (as described in "InstallDispatchHandlers" on page 151).

If the PreDispatchHandlerGlue method is able to retrieve the command number information, it calls the PreDispatchHandler method. That method attempts to resolve the target object for the event. If the event does not specify a target object, MacApp uses the application object as the default target. The PreDispatchHandler method calls the HandleOSAEvent method of the target object. HandleOSAEvent checks whether the object has an attached script and, if it does, gives the script a chance to process the Apple event.

Dispatching Apple Events Directly to an Apple Event Object

If the application does not include MacApp's attachability code, or if an Apple event is not handled by an object with an attached script, the Apple Event Manager makes a callback to the Apple event dispatcher object's DispatchHandlerGlue method, which does the following:

The DispatchHandler method performs several actions:

Although this is a rather complicated algorithm, for most Apple events the DispatchHandler method ends up performing the following actions:

The MScriptableObject::DoScriptCommand method calls other methods of MScriptableObject to handle many specific commands. For example, it calls DoAEClose to handle a cAEClose or cAEQuit command, DoAEMove for a cAEMove command, DoAEOpen for a cAEOpen command, and so on. MacApp classes such as TApplication, TDocument, and TWindow override these methods to open or close windows or documents, quit the application, and so on.

Your classes that support scripting mix in the MScriptableObject class, so they can override these methods too. If a class handles additional commands that aren't supported by MScriptableObject, it can override the DoScriptCommand method. For more information on adding scripting support to your classes, see Chapter 14, "Working With Scripting."

Note
An application may need to create a document that is invisible to the AppleScript interface. For more information, see "A Note on Ghost Documents," beginning on page 184.

The TSetPropertyCommand Class

MacApp makes it easy for your application to set object properties based on received Apple events. A class that wishes to set a property in response to an Apple event overrides the GetObjectProperty method, the SetObjectProperty method, and possibly the GetSetPropertyInfo method. MacApp does the rest.

When MacApp receives a Set Data event specifying a property to be set, it creates a TSetPropertyCommand object to actually set the property. The command's initialization method calls the GetSetPropertyInfo method of the target object to obtain information about the command, including

The GetSetPropertyInfo method of the MScriptableObject class provides default values that may work for your scriptable class--if not, you provide an override method.

For example, in the IconEdit sample application, which uses Apple events to set an icon's color, the TIconDocument class overrides the GetSetPropertyInfo method to supply a command number (cSetColor), and to specify that the context is the icon document, the command is undoable, and the command changes the document. TIconDocument also overrides GetObjectProperty to return the current icon color and SetObjectProperty to set the icon color.

The TSetPropertyCommand sets the property for a list of one or more objects. Before setting the new property, the DoIt method calls the GetObjectProperty method for each object in the list. The command object stores the original property setting so that it can restore the property to its original state for undo.

The next section describes how a TSetPropertyCommand command is created. For more information on getting and setting properties in your application, see "Recipe--Setting Object Properties With Apple Events," beginning on page 355.

The TPropertyAccessor Class

The target specified by an Apple event can be a C++ object (such as a window) or a simpler Apple event object (such as a paragraph of text). The specified operation may also refer to a C++ object (such as activating a window) or to an Apple event object (such as deleting the third word in a paragraph).

To resolve the target object specified by an Apple event, the OSL may call the global Apple event dispatcher object's ObjectAccessor method, passing information about the current contained object. (Note that the OSL actually calls the ObjectAccessorGlue method, which in turn calls ObjectAccessor.) The ObjectAccessor method calls the GetContainedObject method of the current contained object, passing the desired object type, form, and other information.

When the Apple event's specified operation describes a property of the current object, the MScriptableObject:GetContainedObject method returns an object of type TPropertyAccessor. The property accessor object knows which property was specified and keeps a reference to the current object. By returning a property accessor object to handle the event, MacApp can automate the process of responding to Set Property Apple events for classes you have defined, as long as your classes override the GetObjectProperty and SetObjectProperty methods.

Once a target object has been resolved, the global Apple event dispatcher calls the object's HandleScriptCommand method, which eventually calls the target's DoScriptCommand method. For a TPropertyAccessor object, the DoScriptCommand method creates a TSetPropertyCommand command object (described in the previous section) and calls its Process method to immediately execute the command.

IMPORTANT
See "The Command Context for Classes That Handle Apple Events," beginning on page 118, for important information on supplying a context for a command object.

The TClientCommand Class

MacApp provides the TClientCommand class as a base class for commands that send an Apple event to an external process. When any command object is posted, the application calls the command's IsReadyToPost method. The TClientCommand class overrides this method to send its Apple event immediately on posting. TClientCommand can handle any of three sending modes:

kAENoReply
The constant kAENoReply is used when no reply to the sent Apple event is expected. The IsReadyToPost method returns TRUE, and the command is posted to the command queue. When the command is executed, the DoIt method sends the Apple event. No reply is generated.
kAEWaitReply
The constant kAEWaitReply is used when the command should wait for a reply to the sent Apple event. The IsReadyToPost method sends the Apple event and waits for a reply. It then returns TRUE, so the command is posted to the command queue. The default DoIt method does nothing. Your subclass should override DoIt to perform an operation based on the Apple event reply.
kAEQueueReply
The constant kAEQueueReply is used when an asynchronous reply is expected to the sent Apple event. The IsReadyToPost method sends the Apple event, tells the global Apple event dispatcher object that the command is pending, then returns FALSE so the command is not posted to the command queue. When a reply is received at some later point, the global Apple event dispatcher object posts the command. Again, the default DoIt method does nothing. Your subclass can override DoIt to perform an operation based on the Apple event reply.
When you create a command based on the TClientCommand class, you supply the IClientCommand method with an Apple event for the command to send. The sending mode of the apple event is one of the three constants described above: kAENoReply, kAEWaitReply, or kAEQueueReply.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
25 JUL 1996