Team LiB   Previous Section   Next Section

1.2 Apple Events

AppleScript and scriptable programs communicate with each other via Apple events or internal, invisible messages. This section provides an overview of how Apple events are implemented with AppleScript. As this information goes beyond basic script development, some readers may choose to jump ahead to the book's language-reference sections, do some scripting, and then revisit this section at another time.

1.2.1 OSA

The Open Scripting Architecture, which has been present on the Mac since the early 1990s, is Apple Computer's mechanism for making interapplication communication available to a spectrum of scripting languages. AppleScript is the OSA language that Apple provides, but there are other OSA-compliant languages, including UserLand Frontier and JavaScript.[2]

[2] Late night Software, Ltd.'s JavaScript for OSA tool, is accessible from http://www.latenightsw.com.

OSA accomplishes this "the-more-the-merrier" approach to scripting systems by using Apple events as the unifying technology. The situation is similar to Open Database Connectivity (ODBC) on the Windows platform, where any client application can talk to different database management systems using ODBC as a common conduit (as long as ODBC driver software exists for that particular database). In terms of OSA, the conduit (on Mac OS 9) is a scripting component that can convert whatever scripting language is used (AppleScript or JavaScript) into one or more properly constructed Apple events. Figure 1-3 shows the same Apple event being sent to an application in two different scripting languages.

Figure 1-3. OSA scripting tools send Apple events
figs/ascr_0103.gif

Before AppleScripts or other scripting languages can be compiled and run, their corresponding extension files have to be installed (the AppleScript extension is included in an OS 9 installation) and then loaded into the computer's memory. The AppleScript extension or component is depicted in Figure 1-3.

1.2.2 Apple Event Registry

Along with scripting components, another important OSA element is the Apple Event Registry. The Registry is an Apple Computer-maintained database that maps all of the Apple events that the Mac OS standard software uses to a corresponding English-language command. This means that the activate AppleScript command is mapped to an activate Apple event, quit is mapped to a quit Apple event, and so on. You can use the Registry to discover the Apple event codes that are used by the Mac's standard software (such as the Appearance control panel, the ColorSync extension, or Sherlock 2). Section 1.2.4 describes what these codes are.

The AppleScript software development kit (SDK) includes a FileMaker Pro file that contains the Apple Event Registry for AppleScript Version 1.3.4. Go to http://developer.apple.com/sdkfor more SDK information.

To make them easier to understand and incorporate into applications, Apple events are logically grouped into suites or categories, such as the Database Suite, the Standard Suite, and the Text Suite. All Mac applications are required to support four Standard Suite events (open, print, quit, and run; this was the "Required Suite" prior to AppleScript 1.3). This does not mean that all Mac programs do support these events; software developers don't go to jail if they have not implemented these Apple events in their programs. However, this does mean that the vast majority of applications will reliably quit if, for example, your script sends them a quit Apple event.

Applications and scripting additions can (and usually do) define their own Apple events and corresponding human-language commands. For example, the BBEdit text editor supports a subset of the Standard Suite of Apple events that you can look up in the Registry database. BBEdit also contains a set of events and classes known as the BBEdit Suite, which is unique to BBEdit. Table 1-1 shows the Standard Suite Apple events and Apple event classes that BBEdit 5.1 supports. It also shows the Apple events and Apple event classes that are listed in the BBEdit Suite. (Section 1.2.6 describes Apple event classes in more detail.)

Table 1-1. BBEdit 5.1's Standard Suite and BBEdit Suite

BBEdit Standard Suite Events

BBEdit Standard Suite Classes

BBEdit Suite Events

BBEdit Suite Classes

close

application

insert text

character

count

window

insert file

word

delete

document

insert folder

line

get

Recent file

insert project

text

make

 

find

text item

revert

 

replace

selection-object

save

 

find differences

hit

set

 

go to line

 
   

go to function

 
   

go to marker

 
   

select current paragraph

 
   

twiddle

 
   

change case

 
   

shift

 
   

hard wrap

 
   

insert line breaks

 
   

remove line breaks

 
   

unwrap

 
   

zap gremlins

 
   

entab

 
   

detab

 
   

insert glossary entry

 
   

get FTP file

 
   

put FTP file

 

1.2.3 Client/Server

The application or applet that initiates an exchange of Apple events is called the client application. The client requests the help of the server ("do something for me!"). The client's Apple event(s) may request data (e.g., text, database records) or just a sequence of actions that the server should take ("Open a file and send me the paragraph that begins with 'Top-secret information.'"). The client can also be thought of as the Apple event "source," and the server can be thought of as a "target." An application can be both an Apple-event client and a target (if a client receives a reply Apple event, then it's the target of that event).

A machine can send up to about 2,000 Apple events per second (and can be as pokey as about 5 per second). This speed depends on factors such as how quickly the target application can process the Apple event(s).

How Many Apple Events Can Your Machine Send?

An Apple Computer engineer suggests that you use the following code to test how many Apple events a particular machine can send per second:

set start_time to current date

repeat 1000 times

tell application "Finder"

name -- gets the Finder's name, "Finder"

end tell

end repeat

set elapsed_time to (current date) - start_time

display dialog "Average " & 1000 / elapsed_time & " events per¬ second"

This code sends the Finder 1,000 Apple events, and then displays the event-per-second results. Running this as a compiled script out of Script Editor, my machine (a PowerMac 8500 upgraded to a G3 with plenty of memory) registered only 5 per second. However, when saved as an applet and attached to BBEdit, the speed improvement was 20-fold—100 Apple events per second!

Let's drill down further into Apple events. Section 1.2.4 shows you what an Apple event looks like at the system level, using the sleep Apple event, a Finder command, as an example.

1.2.4 Inside an Apple Event

Here's how it works when Script Editor compiles and executes the following code, which comprises a complete compilable script:

tell application "Finder" to sleep

This is what happens:

  1. The AppleScript component has to find out which Apple event lies behind the sleep command. The component knows that the Finder is one of the places it should look for these details, because the Finder is targeted by the tell statement:

    tell application "Finder"...
  2. Remember that sleep is an English-language term for putting the computer to sleep, but it is implemented as the sleep Apple event beneath the surface. Figure 1-4 shows the structure of the sleep Apple event.

    Figure 1-4. A sleep Apple event
    figs/ascr_0104.gif

    The AppleScript component discovers the attributes of the sleep Apple event (e.g., the event id) from a segment of the Finder file called the Apple event terminology extension ('aete') resource. The 'aete' resource maps the sleep script command to the Apple event depicted in Figure 1-4.

  3. The component then sends that Apple event to the Finder, which responds to sleep by powering down the computer.

Here is an explanation of the structure behind the Apple event in Figure 1-4.

Every Apple event is comprised of unique four-character codes that represent the:

  • Event class

  • Event id

  • Address of the target application

The event class represents a grouping of similar Apple events. The event id uniquely identifies the Apple event. The target address is a complex data structure that could contain the application's creator code or its Process Serial Number (PSN) or another piece of identifying information. For example, the sleep Apple event has event class 'fndr' and event id 'slep'. Table 1-2 contains the event classes and event ids for the Standard Suite in the Apple Event Registry. Apple events often get reorganized within different suites when Apple updates its Registry.

Table 1-2. Apple Event Codes for Standard Suite

Event

Event Class

Event Id

Class

Class Id

open
aevt
odoc
application
capp
run
aevt
oapp
document
docu
reopen
aevt
rapp
file
file
print
aevt
pdoc
alias
alis
quit
aevt
quit
selection-object
csel
close
core
clos
window
cwin
count
core
cnte
insertion-point
cins
delete
core
delo
duplicate
core
clon
exist
core
doex
make
core
crel
move
core
move
save
core
save

Most of the time, however, a scripter does not have to deal with event classes and event ids, just their AppleScript language equivalents.

Apple events specify the target programs that should receive the Apple event. Otherwise, your script would cause an execution or runtime error, because the operating system does not know where the Apple event is supposed to go.

The common way to specify the target programs for an Apple event in AppleScript is to use a code such as in Example 1-2. You enclose the Apple events you will send to a program within the tell block, as in Example 1-2, which sends a quit Apple event to "FileMaker Pro".

Example 1-2. A Script Targeting FileMaker Pro
tell application  "FileMaker Pro"

   quit

end tell

The value of the application signature attribute in Figure 1-4 is also a four-character code ('MACS' for the Finder), just like the event class and event id. You might recognize this code as the Finder's creator code.

Each Macintosh file is distinguished by its file type (for example, a text file has file type "TEXT") and creator code (BBEdit's is "R*ch"). This is how the operating system knows which program to open when you double-click a desktop file. It examines the file's creator code.

1.2.5 Apple Event Parameters

Sometimes a lone Apple event like quit or activate will do the trick in a script. At other times, Apple events have to specify Apple event parameters. These are the data the receiver of the Apple event needs to carry out the Apple event's instructions. For instance, if the Example 1-3 script did not include the parameter:

file "mydocument"

then the OS 9 Finder would return an error, because its open Apple event requires a reference to the object(s) to open.

Example 1-3. A Finder open Command
tell application "Finder"

   (*open is the command; file "mydocument" is the parameter *)

   open file "mydocument" 

end tell

Examples in this book will usually include comments explaining code elements. Comment characters in AppleScript are two hyphens (—) for single-line comments and parentheses containing asterisk characters (* *) for multi-line or single-line comments.

Figure 1-5 illustrates the Finder's open Apple event with the reference to the mydocument file.

Figure 1-5. The Finder's open Apple event
figs/ascr_0105.gif

Apple event parameters can include standard data types (e.g., integer or string) or references to Apple event objects, such as a document file. Apple event objects are the items or "nouns" (e.g., a file, a folder, a database record) that some scripts interact with. See Section 1.2.6 for further explanation on handling objects in your scripts.

An Apple event can have more than one required or optional parameter. In another example, if you want your script to tell FileMaker Pro to create a new row in a database, then create is the Apple event (followed by the required keyword new). The create Apple event requires a parameter such as a record object (as in a database record or row). Otherwise, how would the database program know what you wanted to create?

The code in Example 1-4 opens a database file and then creates a new record with empty fields.

Example 1-4. Getting FileMaker to Create a New Database Row
tell application "FileMaker Pro"

   activate --brings the target application to the front

   open file "startupdisk:fm databases:myDB.fm4"

   create new record - "record" is the parameter

end tell

Example 1-4 could use the create command's optional with data parameter to fill the new row with data, thus creating a complete database record.

1.2.6 Apple Event Classes and Objects

You have read about Apple events, which are action words or verbs (activate, delete). Apple event classes (and the objects that are based on those classes) are the nouns that your script might want to manipulate in some manner (see Table 1-1). Example 1-2 told the Finder to open a file object (basically, a file on the desktop). Objects are the data or "things" that you are interested in querying or changing when you send an Apple event to a program.

For example, a script that controls a database program usually deals with database, field, record, or cell objects. An AppleScript that sends commands to a text editor works with character, word, paragraph, and document objects.

These Apple event objects are based on classes or blueprints, such as the file class or the database class. Table 1-3 shows some of the Apple event classes from the Apple Event Registry. The operating system represents these classes internally as four-character codes.

Table 1-3. Examples of Apple Event Classes in OS 9

Class

Four-Character Code

character

'cha '

disk

'cdis'

document

'docu'

file

'file'

folder

'cfol'

paragraph

'cpar'

text

'ctxt'

window

'cwin'

word

'cwor'

A class is a blueprint or data type for a noun or object that you can manipulate with a script.

When an architect creates a blueprint for a structure, all the homes that are subsequently built off of the blueprint are the offspring of her original design. The real wooden, brick, or metallic homes are "instances" (in object-oriented parlance) or objects of the blueprint or class. The architect creates a home class in her blueprint, then the builders generate real home objects based on the original class. For example, the BBEdit text editor defines a word class, which is a bunch of characters that are unbroken by a space, tab, or new-line character (e.g., "apple"). The five characters that make up the word (a,p,p,l,e) are all objects based on the BBEdit character class. So a word object constitutes a group of character objects. If you grouped together several separate character objects they might look like ("a", "p", "p", "l", "e").

For example, when you get the Finder to open a folder with a phrase like:

open folder "my_folder"

then you are telling the Finder to open the folder object (based on the folder class) whose name is "my_folder." This line of code will specifically create a Finder window showing the contents of the folder called "my_folder."

It is always important to describe an Apple event object in your script by its containment hierarchy, which is an exact specification of where an application like the Finder can find the object. Apple event objects are located in a similar manner to taking apart one of those wooden Russian dolls, where the dolls get smaller and smaller until you finally locate the last solid peanut-shaped doll inside of all the bigger ones. In other words, if you wanted to get information about the sender of the first message in your Outlook Express inbox folder, then you couldn't just tell Outlook to:

get the sender of the first message

because the emailer would not know where to look (i.e., in the "inbox" folder) for the email message. Consider Example 1-5, which incompletely describes the containment hierarchy for a file (assuming that the file is not located on the desktop).

Example 1-5. A File-Access Script That Causes an Error
tell application "Finder"

   open file "taxes2000"

end tell

The Finder cannot find this file because the script does not give a complete container reference, as in:

open file "taxes2000" of folder "Taxes" of startup disk

The script will therefore produce a dialog box reporting an error if it is run.

AppleScript has a number of ways to express containment relationships.

file "taxes2000" of folder "Taxes" of startup disk

(an "inside-out" reference). This is like describing the smallest Russian doll as "the tiny doll inside the slightly bigger doll that is contained by all the larger dolls." Or, you can use a possessive form such as:

startup disk's (folder "Taxes"'s file "taxes2000")

Using the possessive style with long container references like this one is usually less readable than the inside-out method.

1.2.7 Elements and Properties

Two other very important characteristics of Apple event objects are elements and properties. The class that these objects are based on defines the object's elements and properties. An object has zero or more of its defined elements, and exactly one each of its properties.

For example, SoundJam™ MP, a digital music player and encoder, defines a playlist window class. These objects are windows that contain lists of audio tracks that can play on the computer. Figure 1-6 shows the definition of the playlist window class from SoundJam's dictionary. (Chapter 2 explains a program's dictionary, which can be viewed by using Script Editor's File Open Dictionary menu command.) A playlist window object has three elements: track, file track, and URL track. Further, playlist windows have a modified property (a true or false value depending on whether the window was modified since it was last saved). playlist windows also inherit several properties from SoundJam™ MP's window class. So a playlist window object can contain zero or more "track" elements, but it only has exactly one "modified" property value.

Figure 1-6. playlist window's elements/properties
figs/ascr_0106.gif

Rest assured that it is easy to grab the values of elements and properties in AppleScript. You can use syntax such as:

tell app "SoundJam™ MP" to get first file track of first playlist window

This code sends SoundJam™ a get Apple event requesting a reference to an element, such as the first file track (an MP3 audio file) in the foremost playlist window that you see when SoundJam™ MP is open. The return value looks like:

'file track id 4 of playlist window id 5 of application "SoundJam™ MP"'

Once your script gets a reference to a track, it can then command SoundJam™ MP to play it with (you guessed it) the play Apple event that SoundJam™ MP defines.

Our introduction to Apple events concludes with a description of the all-important application class, which is the "king of the objects" in a scriptable program. The program that you script, such as application "SoundJam™ MP," is actually an object itself, an "instance" of the SoundJam™ MP application class.

1.2.8 Application Class

Many scriptable applications define an application class, which is the gem to study if you want to automate that program. Your quickest route to the application class is its description in the program's dictionary. We mentioned before that Mac programs can expose an object model to scripting components like AppleScript. An object model is a software abstraction, usually in tree-like form, showing the Apple event objects and Apple events that you can use with a program.

The application class is the root or top-level class in the program's object model. An Apple-event object model shows the application class and all of its elements and properties (if it has any defined elements). Figure 1-7 shows a simple object model for Sherlock 2, the Mac's fancy Find program. Sherlock 2 has three properties and contains zero or more channel elements. (I am sticking to the strict definition of an object's elements, which is that an object can have zero or more of them. In reality, Sherlock 2 always has at least one defined channel, which is the domain that it is searching.)

channel elements are themselves objects with their own properties: "all search sites" and "name" (e.g., the name of one channel is "Internet"). When in doubt about how to script a program, always use the program's dictionary to examine its application class. The elements and properties of the application class are the things that you will be able to control and derive values from with your AppleScripts.

If you are on friendly terms with an illustration tool, then it helps to sketch out an object model of a program you are trying to script.

Figure 1-7. Sherlock 2's application class
figs/ascr_0107.gif
    Team LiB   Previous Section   Next Section