High Level Events
Volume Number: 7
Issue Number: 11
Column Tag: Jörg's Folder
Related Info: Event Manager Apple Event Mgr Edition Manager
High Level Events
By Jörg Langowski, MacTutor Editorial Board
High Level Events”
You’ve seen System 7 for quite a while now. Over a year if you’ve had access to
‘official’ developer information, and over half a year if you’ve had to wait for the
official release. You’ve had time to familiarize yourself with the most prominent
features of the new system: an improved user interface, aliases, file sharing, virtual
memory, and some applications that won’t work anymore
To me, the most important new addition in the System 7 release is the possibility
of inter-program communication through ‘AppleEvents’, or high-level events. This
feature is not as directly visible as the others, and only few programs so far make use
of it, none of them to anything near its full capacity (not that I know of). But it may
well be that AppleEvents are to the Macintosh in 1991 what the Macintosh was to
computing in 1984.
To explain this enthusiastic remark, let’s compare the old (up to System 6) and
new (System 7 and later) programming paradigms on the Macintosh.
Event Loops - System 6 and 7
The classical System 6 event loop waits for an event like mouse down, key down,
etc., and calls a handler routine corresponding to that event. This works well as long as
the user interacts directly with one program on the Macintosh at a time. You can,
however, easily think of situations that this type of event loop cannot easily handle. One
very simple example is the Shutdown command in the Finder’s Special menu. This
command, issued under Sys6/Multi finder, somehow had to tell all the open applications
to quit - and in doing so, clean up their act, saving files etc. - before shutting down the
machine.
As users of foreign system versions with US programs may very well
remember, in the early times of Multifinder the shutdown command would often not
work: E.g., in France the application didn’t have a ‘’File’, but a ‘Fichier’ menu, in
which there was no such item as ‘Quit’, but ‘Quitter’. Now, since the Finder was looking
for the item and menu number of ‘Quit’ in the ‘File’ menu to fake a menu selection in
order to force the application to quit, that mechanism wouldn’t work if the Quit item
and/or File menu couldn’t be found. There was a work around then, by adding a resource
that could contain strings for the ‘File’ menu and item such as ‘Open’, ‘Print’, ‘Quit’ in
all sorts of possible languages; but this solution was awkward since that resource would
have to be changed every time you hit upon a program localized for a different language.
A much more elegant solution is to define a new type of event to which the
application has to respond, no matter what the localization, thereby isolating the
program’s action (quitting, opening a document) from the particular implementation of
the user interface (language in which the menu is written). The Finder would send a
‘quit’ event to an application, and the application would understand it and quit. Opening
documents would work pretty much the same way: if a user opens a document in the
Finder, and the application is already open, an ‘open document’ event would be sent to it
and the program would open the new document (if it understands the event).
Since the Finder is just a program as well, one might as well generalize this
event-sending protocol and allow any program to send a message to any other program.
For instance, imagine a word processor document in which a table is pasted that was
part of a spreadsheet. When the user changes some data in the table, the word processor
program could send messages to the spreadsheet program to recalculate the table. The
two programs might be running on the same Macintosh, or even on two different Macs
connected through a network. Thus, one Macintosh can request ‘services’ on another one
without having all the programs reside on its own hard disk, and without loading the
program into its own memory first. Even more interesting, a program can send events
to itself! This way, you can imagine a complete disconnection between user-produced
events (menu selections, key downs etc.) and their handlers. When, for instance, the
user selects ‘Quit’ from the file menu, the event loop does not directly call a routine
that terminates the program, but sends a high-level ‘quit’ event to itself. That event
will be received on one of the next WaitNextEvent calls, and the action (in this case, exit
the program) is taken by the high-level event handler.
This is the principal difference between the pre-System 7 and the new
programming paradigm: it is now possible to write an event loop that does not take any
action directly, but in response to user actions posts high-level events to itself, to
which the handlers will respond. You see immediately the possibilities that this
mechanism gives: not only can programs communicate with each other, but you might go
as far as controlling a program on one computer through the network from a user
interface residing on another machine.
The Structure of a High-level Event
Inside Macintosh Vol. VI (which by the way is thicker than the first three
volumes of Inside Mac taken together) devotes almost four hundred of its one
thousand-odd pages to things connected with high-level event handling and
program-to-program communication. That’s one indication how seriously Apple takes
this business. The Apple Event Manager chapter explains how a high-level event looks
like, and I’ll give a quick overview.
A high-level event has an event class and an event ID. Both are 32 bit integers,
or rather, four-character constants just like the creator and type signatures of a
Macintosh file. Typical event classes are
/* 1 */
kCoreEventClass = 'aevt';
kAEFinderEvents = 'FNDR';
kSectionEventMsgClass = 'sect';
(The constant names are the ones defined in the MPW Pascal and C interfaces).
The core event class, ‘aevt’, contains events that correspond to very basic actions that
most programs should understand. In fact, a System 7-aware application has to support
the four events whose IDs are given by the following constants:
/* 2 */
kAEOpenApplication = 'oapp';
kAEOpenDocuments = 'odoc';
kAEPrintDocuments = 'pdoc';
kAEQuitApplication = 'quit';
The ‘FNDR’ event class corresponds to events that the finder understands; so for
instance you may send a ‘shut’ event to the Finder, and it will faithfully shut down your
machine. ‘sect’ events are used by the Edition manager, another part of
program-to-program communication which supports different applications working on
the same document. We’ll come to that later.
Data Descriptors
An Apple event has an extremely interesting and versatile structure. The
fundamental data structure from which the Apple event and all data contained in it are
built up is the descriptor record:
{3}
TYPE AEDesc =
RECORD
descriptorType: DescType;
dataHandle: Handle
END;
The descriptor type is a 4 byte character constant describing the data type; for
instance, ‘long’ designates a 32-bit integer. ‘aevt’ means that the data referenced by
the handle is an Apple event record; the record itself is a list of descriptor records.
Each descriptor record is preceded by a keyword that identifies what the data is good for
(it took me a while to understand this - the descriptor type specifies the format of the
data, and the keyword its purpose). Thus, a ‘quit’ event record might contain the
following data:
evcl’ ‘type’ -> ‘aevt’
‘evid’ ‘type’ -> ‘quit’
‘addr’ ‘sign’ -> ‘JLMT’
‘evcl’ means that the event class descriptor record follows; ‘evid’ signifies the
event ID, and ‘addr’ the address of the target application receiving the event. You
immediately understand why such a rather complicated data structure was chosen for
Apple events when you look at the third item in the list. ‘addr’ can be followed by a
descriptor identifying the signature of another application residing on the same
Macintosh, in which case the descriptor type is ‘sign’ and the handle points to the
four-byte application signature; but you could also have the ‘psn ‘ descriptor and the