Recent from talks
Nothing was collected or created yet.
Apple event
View on WikipediaApple events are the message-based interprocess communication mechanism in Mac OS, first making an appearance in System 7 and supported by every version of the classic Mac OS since then and by macOS. Apple events describe "high-level" events such as "open document" or "print file", whereas earlier OSs had supported much more basic events, namely "click" and "keypress". Apple events form the basis of the Mac OS scripting system, the Open Scripting Architecture (the primary language of such being AppleScript).
The starting point is a dynamically-typed, extensible descriptor format called an AEDesc, which is just an OSType code specifying the data type, together with a block of type-dependent data. For instance, the OSType code inte indicates that the data was a four-byte signed integer in big-endian format.
Besides predefined type codes for various common simple types, there are two predefined structured descriptor types: an AERecord, which has data type reco (record), and AEList with type list (list or array). The internal structure of these contain recursively-nested AEDescs, while the AERecord also associates each element with a unique record field ID, which is an OSType. The Apple Event Manager provides API calls to construct these structures, as well as extract their contents and query the type of contents they hold.
The Apple Event Manager also supports coercions, which converts AEDescs from one data type to another. In addition to standard coercions, for instance between integer and real types, applications can install their own coercion handler callbacks, which handle conversions to and from custom data types.
An Apple event proper is an AERecord with fields that depended on the purpose of the event. In addition, it has attributes (which are distinct from record fields, which are now called the parameters of the event) from a set predefined by the Apple Event Manager. These specify what the event is supposed to do (through event class and event ID), the target address to which the event is to be sent (which could be a process on the local or a remote machine), and various other options for handling it. Remote machines initially had to be connected via AppleTalk, but Mac OS 9 added the option for connections via TCP/IP.
After sending an Apple event to its target process, the sending process can elect to receive a reply to an Apple event. This can contain various bits of information returned from the target about the processing of the original event, including an error code indicating success/failure, any information requested by the original event, and/or other appropriate information.
Apple events are the foundation of the AppleEvent Object Model, which in turn is the foundation of the OSA and AppleScript. As of 2016[update], the official implementation of the Apple Event Manager API is available in C and its descendants, including C++. Official bindings are also provided for Objective-C and Swift through the Cocoa API. Unofficial bindings also exist for other languages (with varying degrees of limitation), including Perl, UserTalk, Ruby and Python.
Object Model
[edit]The AppleEvent Object Model (AEOM) was a set of protocols built on top of AppleEvents by which applications running under classic Mac OS and macOS could control each other's functions. Applications that implemented some part of the AEOM were called scriptable because they could be controlled via AppleScript. Unfortunately, scriptability support remained patchy and inconsistent throughout the history of classic Mac OS.
The AEOM provided a syntactic layer under which any application could publish its internal objects, allowing those objects to be manipulated in a standardized way. Unlike other similar-sounding concepts such as ToolTalk, there was a clear, orthogonal distinction between nouns and verbs; thus, instead of providing separate commands for "close document" and "close window", there was a single "close" verb which could take references to "document" or "window" objects, or any other object that the application published.
The objects that an application made available through its AEOM support were arranged in a hierarchy. At the top was the application itself, referenced via a null object descriptor. Other objects were referenced by (recursively) specifying their parent object, together with other information identifying it as a child of that parent, all collected in an AERecord. An iterator was provided by parents to enumerate their children, or children of a certain class, allowing applications to address a set of elements. The system was generally similar to the Document Object Model used in XML, although with some differences in access patterns.
Each object could have elements and properties; elements were other objects, which might be created or deleted, while properties could not be created or deleted but had values which might be interrogated or changed. For instance, the application might have one or more window elements representing windows showing the contents of currently-open documents. These windows might have properties such as their title, position and size.
An application could define custom verbs for operating on its objects. The AEOM also specified various standard verbs which (it was hoped) applications would implement in a consistent fashion, such as open, close, create element, delete, set data, and get data. Each verb was defined as an AppleEvent of a specific type and class, together with particular parameters of particular types that were expected to be present. For instance, the "get data" event was the standard means for obtaining the value of a property: it took essentially one parameter, which was an object descriptor identifying the property to be queried. The value of that property would be returned in the reply event. The "set data" event took two parameters, the object descriptor for the property to set and the new value for the property; the reply event was only expected to return a success status or failure error code.
The entire AppleEvent architecture identifies things using four-byte OSType codes, studiously avoiding actual words or phrases in English (or any other language). Instead, the correspondence between internal AppleEvent codes and external natural-language descriptions is specified through the aete (AppleEvent Terminology Extension) resource — the "extension" being to the standard terminology built into AppleScript itself. An application may provide multiple 'aete' resources for multiple languages, in keeping with the original multilingual design of AppleScript itself
For instance, consider the following AppleScript sequence controlling a fictional drawing application:
tell application "ScriptableDraw"
set background color of window "New Drawing" to background color of window "Old Drawing"
end tell
This actually involves the sending of two AppleEvents to the target application (and the receipt of their corresponding replies): first, a get-data event is sent to retrieve the background color property of the window identified by the name "Old Drawing"; then a set-data event is sent to apply the value returned as the background color property of the window named "New Drawing".
Since this sort of access pattern was typical, AppleScript made widespread use of the tell statement, which switched the context to the named object in a fashion similar to the with statement found in Visual Basic or Pascal. All commands after the tell to the corresponding end tell would be sent to the object named in the tell, instead of the default object, which was the current application.
Object descriptors allowed the identification of objects in various ways. The most interesting one was using a where-clause (which translated into AppleScript terminology as a filter expression). For instance, the AppleScript 1.0 SDK shipped with the source code for an example application called the Scriptable Text Editor, which would respond to scripts such as:
tell application "Scriptable Text Editor"
tell window "Example Document"
set text style of every word whose length > 7 to bold
end tell
end tell
Even today, it is rare to find this kind of power in general-purpose scripting languages outside of SQL.
Adding support for the AEOM in the classic Mac OS was a difficult process. Application developers had to identify their objects and hand-write code to allow them to be addressed. This typically took the form of code for returning the "next" object of a particular type, allowing AppleScript to iterate over them. But since the OS did not contain an object model, this work was left entirely to the developers, many of whom did not implement it. Oddly, even Apple's own application framework, MacApp, did not offer such a model except for the GUI objects it knew about, once again making the developer do most of the work of scripting the objects representing the data itself. Largely for these reasons, AppleScript support was not very widespread.
Apple did attempt to address this problem with the introduction of various object "suites", which represented standard objects and verbs that were expected to be supported by different types of applications. For instance, all applications were expected to support the "core suite", and any application editing text was expected to support the "text suite". By selecting a suitable set of suites, the developer could at least reduce the workload of planning how to expose their objects. Yet because these objects were generally not part of the system itself (with the exception of the severely limited TextEdit editor), the actual implementation was left to the developer.
Applications developed in Cocoa, the system formerly known as OpenStep, offer a rich object runtime that can be queried from any other application. This makes implementation of the AEOM considerably easier, dramatically reducing the amount of code needed in the average application. Additionally the majority of Cocoa applications are constructed primarily from Cocoa-standard objects, all of which were upgraded to offer fairly extensive scriptability. This extends not only to GUI objects as under MacApp, but also to data objects inside them, including text, tables and various list objects. A text file is used to map the internal "object-like" names onto human-readable versions, and in most cases creating this is all that is needed to add fairly substantial scriptability to most programs.
While Cocoa applications are not AEOM based, and often use subtly different objects than Apple's originally defined standard objects, Cocoa apps are generally much more scriptable than their "classic" counterparts—in fact, it is uncommon to find a Cocoa application that is not scriptable to some degree.
Scripting Bridge
[edit]The Scripting Bridge is a macOS framework which allows applications to communicate with each other without the use of an intermediary scripting language such as AppleScript. Like AppleScript, the Scripting Bridge uses Apple events for inter-application communication.[1]
The Scripting Bridge is typically used from Objective-C,[1] but can be used in other programming languages through an Objective-C bridge such as MacRuby[2] and PyObjC.
Further reading
[edit]- Cook, William R. (September 29, 2006), "AppleScript" (PDF), Proceedings of the third ACM SIGPLAN conference on History of programming languages, University of Texas at Austin, pp. 1–1–1–21, CiteSeerX 10.1.1.76.6993, doi:10.1145/1238844.1238845, ISBN 9781595937667, S2CID 220938191, retrieved May 9, 2009
{{citation}}: CS1 maint: location missing publisher (link). In particular, see Section 2.3 “Apple Events” (pages 9–13), though the history and importance of Apple Events is also discussed elsewhere in the paper.
References
[edit]- ^ a b "Scripting Bridge". Apple Developer documentation. Retrieved 2023-02-04.
- ^ Paul, Ryan (2011-09-27). "Tutorial: OS X automation with MacRuby and the Scripting Bridge". Ars Technica. Retrieved 2023-02-04.
External links
[edit]Apple event
View on GrokipediaOverview
Definition and Purpose
Apple events are a message-based interprocess communication (IPC) mechanism designed for Mac OS and macOS, enabling applications to send structured requests and receive corresponding responses across process boundaries.[5] They conform to the Apple Event Interprocess Messaging Protocol (AEIMP), which defines a standardized format for high-level events that specify complex operations and data transport.[3] This system provides a robust foundation for interapplication communication (IAC), allowing one application to act as a client requesting services from another acting as a server.[3] The primary purpose of Apple events is to facilitate automation, scripting, and seamless data exchange between applications without relying on direct API calls, supporting both local interactions and remote communication over networks.[3] By abstracting low-level IPC details, they enable developers to create extensible, object-oriented messaging that addresses specific elements within target applications, such as documents or windows.[5] Key benefits include a high-level abstraction that simplifies integration, support for object-oriented addressing via the Apple Event Object Model, and extensibility through custom event definitions alongside standard suites like the Required and Core suites.[3] This promotes interoperability and scriptability, particularly with tools like AppleScript.[3] Apple events were initially introduced in 1991 with System 7 as a core component of the Open Scripting Architecture (OSA), marking a significant advancement in Macintosh interapplication communication by integrating messaging with scripting capabilities.[3]Historical Development
Apple Events originated in the late 1980s as a key component of Apple's initiative to standardize interapplication communication on the Macintosh platform, addressing the limitations of prior ad-hoc methods like the Edition Manager and publish-subscribe protocols. They were formally introduced with the release of System 7 on May 13, 1991, forming the foundation of the Open Scripting Architecture (OSA) to enable seamless automation and data exchange between applications. This shift replaced fragmented scripting approaches, allowing developers to create more integrated and extensible software ecosystems.[6][3] Early implementations emphasized networking capabilities, with initial support for remote Apple Events transmitted over AppleTalk, facilitating distributed computing in local networks. By 1999, with the advent of Mac OS 9, Apple Events evolved to include TCP/IP connectivity options for remote interactions, broadening their applicability beyond proprietary protocols and aligning with emerging internet standards. This persistence continued into the modern era, as Apple Events remained a core feature in macOS (initially Mac OS X) starting with version 10.0 in March 2001, ensuring backward compatibility for legacy applications while integrating with Unix-based underpinnings.[7][8] A pivotal evolution occurred in 1993 with the integration of AppleScript, Apple's natural-language scripting system released alongside System 7.1.1, which leveraged Apple Events to provide accessible, user-level automation for non-programmers. This synergy extended the OSA framework to support additional languages, such as JavaScript for Automation introduced in macOS 10.10, promoting a modular environment for diverse scripting implementations. The adoption of Apple Events in prominent applications, including Microsoft Office for Mac from its early versions, underscored their role in fostering cross-vendor interoperability and workflow efficiency.[9][10][11] The development of Apple Events reflected Apple's broader vision for intuitive computing, influenced by co-founder Steve Jobs' advocacy for user-friendly automation tools that empowered end-users without requiring deep technical expertise. Later enhancements, such as Scripting Bridge in macOS 10.5, provided an Objective-C interface to simplify access for contemporary developers.[12]Technical Architecture
Core Components and Data Structures
The Apple Event Manager (AEM) serves as the foundational framework within macOS for handling interapplication communication through Apple events, providing APIs for creating, sending, receiving, and processing these high-level events. It integrates with the Open Scripting Architecture (OSA) to enable structured data exchange between applications, supporting both local and remote interactions via TCP/IP using the EPPC protocol and other networking stacks, with remote access requiring explicit enabling in system settings.[13] The AEM manages event lifecycle aspects, including queuing incoming high-level events and dispatching them to appropriate handlers based on event attributes. Event queues in the AEM facilitate asynchronous processing by buffering incoming Apple events, which are identified as high-level events (with message class kHighLevelEvent) in an application's event loop. Upon receipt, the AESend function can queue replies using flags like kAEQueueReply, storing them under the core event class kCoreEventClass and event ID kAEAnswer for later retrieval. Dispatch mechanisms rely on dispatch tables: the Apple event dispatch table maps event class and ID combinations to handler functions installed via AEInstallEventHandler, while the object accessor dispatch table routes object specifier resolutions to custom accessor functions via AEInstallObjectAccessor. The AEProcessAppleEvent function orchestrates this by extracting event attributes, locating the handler, and invoking it, ensuring thread-safe processing within the application's main loop. Central to Apple events are data structures that encapsulate typed information, starting with the AEDesc (Apple event descriptor), which acts as the basic building block for all event components. An AEDesc is a structure consisting of a DescType (a four-character code identifying the data type) and opaque data storage, functioning as a tagged union that supports various primitive and composite types such as text (typeChar), integers (typeSInt16 or typeLongInteger), floating-point numbers (typeFloat or typeDouble), booleans (typeBoolean), and enumerated values (typeEnumerated). For example, text data might use typeChar with a handle to a Pascal string, while numeric data employs inline storage for efficiency in small values. This design allows descriptors to represent diverse information flexibly, with the Apple Event Manager providing functions like AECreateDesc to construct them and AEDisposeDesc to manage memory. More complex structures build upon AEDesc, including AERecord for keyword-parameterized collections and AEList (implemented as AEDescList) for ordered sequences. An AERecord is a type alias for AEDescList but specialized for Apple events, where parameters are stored as keyword-addressed descriptors (using four-character keywords like keyDirectObject); it has descriptor type typeAERecord and supports extraction via functions like AEGetKeyDesc. This enables structured parameterization, such as specifying a direct object and optional properties in an event. In contrast, an AEList, or AEDescList, holds an unordered or ordered list of AEDesc elements under type typeAEList, created with AECreateList and manipulated via AEPutDesc or AEGetDescAtIndex for positional access. These lists are essential for representing arrays or variadic data, like multiple selected items, without keyword dependencies. The coercion system in the AEM provides automatic type conversion between compatible AEDesc types, enhancing interoperability by applying predefined rules for common transformations. For instance, a text descriptor (typeChar) containing "123" can be coerced to an integer (typeLongInteger) via the built-in handler, using functions like AECoerceDesc that consult the system or application coercion dispatch table. Developers can extend this by installing custom handlers with AEInstallCoercionHandler for application-specific types, ensuring the output descriptor matches the requested type while handling errors like errAECoercionFail if conversion is impossible. This mechanism underpins seamless data handling in scripting and event processing, prioritizing efficiency by preferring pointer-based coercions where possible. Addressing in Apple events employs object specifiers to precisely target elements within an application's object model, such as a specific document or window, rather than the application as a whole. An object specifier is an AERecord of type typeObjectSpecifier, containing four key parameters: keyAEDesiredClass (the target object's class, e.g., cDocument), keyAEContainer (a nested specifier or null for the application root), keyAEKeyForm (the selection method, such as formName for named objects or formAbsolutePosition for indexed ones), and keyAEKeyData (the actual selector data, like a string name or integer index). Resolution occurs via AEResolve, which recursively traverses the hierarchy by invoking object accessor functions to yield tokens (AEDesc of custom types) representing located objects, enabling fine-grained operations like retrieving or modifying a window within a document. This specifier system supports hierarchical addressing, with support for logical descriptors in AEDescList for complex queries like unions or intersections.Event Format and Parameters
Apple events are structured as messages consisting of a four-character event class code that identifies the category of the event and a four-character event ID, known as the selector, that specifies the particular action to perform. For standard suite events, the event class is typically 'aevt', representing the core event class, while selectors include 'oapp' for opening an application, 'odoc' for opening documents, and 'pdoc' for printing documents. Transaction IDs are included to uniquely identify events and their corresponding replies, enabling the sender to match responses to original requests. Parameters in an Apple event are organized as keyword-based pairs, where each keyword is a four-character code identifying the parameter's role, and the value is a descriptor containing the data. Common keywords include '----' for the direct object parameter, which typically holds the primary data or object acted upon, such as a list of documents to open, and 'insh' for the insertion location, specifying where data should be placed in the target application. Reply events follow the same structure but use the event class 'aevt' and selector 'ansr', carrying results or error information; error codes, such as those defined in MacErrors.h (e.g., errAENotASuitedApp indicating the target application cannot handle the event), are conveyed via the keyErrorNumber parameter. These descriptors for parameter values are typically Apple event descriptors (AEDesc), which encapsulate the data in a type-length-value format. Attributes provide metadata about the event itself and are also stored as keyword-descriptor pairs within the event record. Key attributes include the target process specifier, often using the keyword for the address attribute to identify the recipient by process serial number or application signature; the return ID (keyword 'rtid'), which allows asynchronous handling by linking replies to the original event; and the transaction ID (keyword 'tran') for tracking. Additional attributes cover event timing via the event time keyword and priority levels to influence dispatch order, though priority is generally managed by the system. In legacy network scenarios, Apple events were encapsulated within AppleTalk packets using the Program-to-Program Communication (PPC) Toolbox to enable inter-machine communication, requiring program linking for remote access. In modern macOS contexts, Apple events are primarily local and serialized through the Apple Event Manager's descriptor system, akin to the message serialization in XPC services for interprocess communication, though XPC has largely supplanted Apple events for new development.Implementation
Sending Apple Events
Sending Apple events involves constructing an event structure, specifying the target application, adding necessary parameters using Apple Event descriptors (AEDesc), and dispatching the event via the AESend function from the Apple Event Manager.[14] This process enables interapplication communication on macOS, allowing one application to request actions from another.[2] To begin, create an address descriptor (AEAddressDesc) for the target application, typically using its creator code (a four-character signature) or process serial number. For example, the Finder's creator code is 'MACS', which can be used with the typeApplSignature descriptor type.[14] The AECreateDesc function constructs basic AEDesc structures for parameters, such as file paths represented as typeFSS (file system specification) or typeAlias descriptors. These descriptors encapsulate data with a type code, pointer to the data, and size, ensuring type-safe transmission.[14] Next, build the Apple event using AECreateAppleEvent, providing the event class (e.g., kCoreEventClass for standard events), event ID (e.g., kAEOpenDocuments for opening files), target address, return ID, and transaction ID. Add parameters to the event with functions like AEPutParamPtr for simple data or AEPutParamDesc for complex descriptors, using keywords such as keyDirectObject for the primary parameter.[14] For lists, like multiple files in an open event, employ AEDesc lists created via AECreateList.[15] Dispatch the event with AESend, which takes the Apple event, a reply event pointer (if expecting a response), send mode flags, priority, timeout in ticks, an idle procedure for asynchronous waits, and a filter procedure. Common flags include kAEWaitReply for synchronous operation (waiting up to the specified timeout) and kAENoReply for fire-and-forget sends; asynchronous sends use kAENoWaitReply combined with a callback via the idle or filter procs to handle replies later.[14] The send priority defaults to kAENormalPriority, and timeouts prevent indefinite hangs, such as kNoTimeOut for indefinite waits in interactive scenarios.[16] Error handling is essential, as AESend returns an OSErr code; successful sends yield noErr, while common failures include procNotFound (-1728) if the target lacks the handler, errAETimeout (-1712) on timeouts, or connectionInvalid (-1700) for unreachable targets.[14] For replies, inspect the reply event with AEGetParamPtr to retrieve error numbers under the keyErrorNumber keyword, and implement retries for transient errors like timeouts by re-sending after a delay. Always dispose of AEDesc and AERecord structures with AEDisposeDesc to free memory. A representative example is sending an 'open documents' event to the Finder to reveal a file, using a file path as the direct object parameter. The following C code snippet illustrates this (assuming prior inclusion of <AE/AE.h> and <CoreFoundation/CoreFoundation.h> for modern file handling):#include <AE/AE.h>
#include <CoreFoundation/CoreFoundation.h>
// Assume 'filePath' is a C string (const char*) for the target file path
AEDesc targetDesc, fileDesc, reply;
AppleEvent openEvent;
OSErr err;
CFURLRef url;
CFStringRef urlStr;
const char *urlCString;
size_t urlLen;
// Create target address for Finder ('MACS')
err = AECreateDesc(typeApplSignature, "MACS", 4, &targetDesc);
if (err != noErr) return err;
// Create file descriptor using modern URL-based approach
url = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)filePath, strlen(filePath), false);
if (!url) return errAEBadURL; // Or appropriate error
urlStr = CFURLCopyAbsoluteString(url);
CFRelease(url);
if (!urlStr) return memFullErr;
urlCString = CFStringGetCStringPtr(urlStr, kCFStringEncodingUTF8);
if (!urlCString) {
CFRelease(urlStr);
return errAEBadURL;
}
urlLen = strlen(urlCString) + 1; // Include null terminator
err = AECreateDesc(typeFileURL, urlCString, urlLen, &fileDesc);
CFRelease(urlStr);
if (err != noErr) { AEDisposeDesc(&targetDesc); return err; }
// Create the open event
err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &targetDesc,
kAutoGenerateReturnID, kAnyTransactionID, &openEvent);
AEDisposeDesc(&targetDesc);
if (err != noErr) { AEDisposeDesc(&fileDesc); return err; }
// Add file as direct parameter (wrap in list if multiple)
AEDescList fileList;
err = AECreateList(NULL, 0, true, &fileList);
if (err != noErr) goto cleanup;
err = AEPutDesc(&fileList, 1, &fileDesc);
if (err != noErr) goto cleanup;
err = AEPutDesc(&openEvent, keyDirectObject, &fileList);
AEDisposeDesc(&fileList);
AEDisposeDesc(&fileDesc);
if (err != noErr) goto cleanup;
// Send synchronously with 30-second timeout
err = AESend(&openEvent, &reply, kAEWaitReply, kAENormalPriority,
30 * 60, NULL, NULL); // 30 seconds = 1800 ticks at 60Hz
// Handle reply/errors here, e.g., if (err == noErr) { /* process reply */ }
cleanup:
AEDisposeDesc(&openEvent);
if (reply.descriptorType != typeNull) AEDisposeDesc(&reply);
return err;
#include <AE/AE.h>
#include <CoreFoundation/CoreFoundation.h>
// Assume 'filePath' is a C string (const char*) for the target file path
AEDesc targetDesc, fileDesc, reply;
AppleEvent openEvent;
OSErr err;
CFURLRef url;
CFStringRef urlStr;
const char *urlCString;
size_t urlLen;
// Create target address for Finder ('MACS')
err = AECreateDesc(typeApplSignature, "MACS", 4, &targetDesc);
if (err != noErr) return err;
// Create file descriptor using modern URL-based approach
url = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8 *)filePath, strlen(filePath), false);
if (!url) return errAEBadURL; // Or appropriate error
urlStr = CFURLCopyAbsoluteString(url);
CFRelease(url);
if (!urlStr) return memFullErr;
urlCString = CFStringGetCStringPtr(urlStr, kCFStringEncodingUTF8);
if (!urlCString) {
CFRelease(urlStr);
return errAEBadURL;
}
urlLen = strlen(urlCString) + 1; // Include null terminator
err = AECreateDesc(typeFileURL, urlCString, urlLen, &fileDesc);
CFRelease(urlStr);
if (err != noErr) { AEDisposeDesc(&targetDesc); return err; }
// Create the open event
err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &targetDesc,
kAutoGenerateReturnID, kAnyTransactionID, &openEvent);
AEDisposeDesc(&targetDesc);
if (err != noErr) { AEDisposeDesc(&fileDesc); return err; }
// Add file as direct parameter (wrap in list if multiple)
AEDescList fileList;
err = AECreateList(NULL, 0, true, &fileList);
if (err != noErr) goto cleanup;
err = AEPutDesc(&fileList, 1, &fileDesc);
if (err != noErr) goto cleanup;
err = AEPutDesc(&openEvent, keyDirectObject, &fileList);
AEDisposeDesc(&fileList);
AEDisposeDesc(&fileDesc);
if (err != noErr) goto cleanup;
// Send synchronously with 30-second timeout
err = AESend(&openEvent, &reply, kAEWaitReply, kAENormalPriority,
30 * 60, NULL, NULL); // 30 seconds = 1800 ticks at 60Hz
// Handle reply/errors here, e.g., if (err == noErr) { /* process reply */ }
cleanup:
AEDisposeDesc(&openEvent);
if (reply.descriptorType != typeNull) AEDisposeDesc(&reply);
return err;
Receiving and Handling Events
Applications register to receive Apple events by installing event handlers in the Apple event dispatch table using theAEInstallEventHandler function from the Apple Event Manager, which is part of the Core Services framework and accessible via AppleEvent.h in both Carbon and Cocoa environments.[17] This function takes parameters including the event class (an AEEventClass such as kAECoreSuite), the event ID (an AEEventID such as kAEOpenDocuments), a universal procedure pointer to the handler routine (AEEventHandlerProcPtr), a reference constant for the handler, and a boolean indicating whether to install in the system or application dispatch table (typically false for the application's table).[17] Handlers can be installed for specific class/ID pairs or using wildcards like typeWildCard to catch multiple events, with the handler required to return errAEEventNotHandled if it does not process a wildcard-matched event.[17] Installation typically occurs during application initialization to ensure the app can respond to required core events like opening documents.[18]
Once registered, the macOS system routes incoming Apple events to the target application's event loop as high-level events of kind kHighLevelEvent.[18] In the main event loop, applications detect these events using functions like WaitNextEvent or RunAppModalLoop and invoke AEProcessAppleEvent to dispatch the event to the appropriate handler based on its class and ID.[19] This function searches the application's dispatch table first, then the system table if no match is found, and calls the matching handler if present; it integrates seamlessly with the event loop to handle events asynchronously without blocking the UI.[19][18]
Within the event handler routine, which receives the incoming AppleEvent, a reply AppleEvent, and the reference constant, applications extract parameters using AEGetParamDesc to retrieve descriptor records (AEDesc) for specific keywords like keyDirectObject or keyAEList.[20] This function coerces data to the requested type (e.g., typeFSS for file system specifiers) and returns an AEDesc or, for keyword-based parameters, an AERecord structure that organizes multiple descriptors.[20] Developers must parse object specifiers in parameters using AEResolve to identify and access the targeted objects in the application's data model.[18] Processing then proceeds via a switch statement or similar logic on the event class and ID to execute the requested action, such as opening a document or performing a quit operation, while checking for missed parameters with attributes like keyMissedKeywordAttr.[18]
To respond, handlers construct a reply event by adding parameters with functions like AEPutParamPtr or AEPutParamDesc, inserting results (e.g., error codes or return data) under keywords such as keyDirectObject, and returning an OSErr result like noErr to indicate success or errAEEventNotHandled if unprocessed.[18] The system automatically sends the reply back to the sender after the handler completes.[18]
For advanced scenarios, applications can suspend event handling using AESuspendTheCurrentEvent to defer processing of the current event, which is useful for multi-session servers or internal queuing, and resume it later with AEResumeTheCurrentEvent by providing the event, reply, dispatcher, and reference constant.[18] In macOS, since version 10.2, Apple event functions including handler installation and dispatching are thread-safe, but handlers are invoked on the thread processing the event—typically the main thread—requiring developers to consider concurrency when accessing shared resources in multi-threaded applications.[17][18]
Apple Event Object Model
Structure and Standards
The Apple Event Object Model (AEOM) establishes a container-based framework that conceptualizes the elements of an application as a hierarchical structure, enabling precise navigation and manipulation through Apple events. In this model, objects such as documents, windows, paragraphs, and characters are treated as contained within parent containers, forming a tree-like organization that reflects the application's internal data model. For instance, a paragraph object can be addressed as an element contained within a specific document, allowing events to target nested components systematically. This hierarchical approach facilitates addressing complex object relationships without requiring low-level details of the application's implementation.[3] Standard verbs in the AEOM are organized into suites that define actions—or "noun-verb" interactions—performed on objects within the hierarchy. The Required Suite mandates support for fundamental application-level operations, including opening the application without documents ('oapp'), opening specified documents ('odoc'), printing documents ('pdoc'), and quitting the application ('quit'). These verbs ensure basic interoperability for server applications. Additionally, relational operators such as "before" and "after" are integral to object specifiers, enabling relative addressing of elements; for example, an event can target the object immediately preceding or following a specified item in a container.[3][21] The AEOM employs suites to group related verbs and object classes, promoting standardization across applications. The Core Suite (AECoreSuite) provides foundational verbs for object manipulation, such as retrieving data from an object ('getd') and setting properties, which form the basis for more advanced interactions. Specialized suites extend this core; for example, applications like TextEdit incorporate the Miscellaneous Suite ('misc') for verbs like counting elements in a container and the Edit Suite ('edit') for clipboard operations including copy, cut, and paste. These suites, along with others in functional areas like text or database handling, are outlined in the Apple Event Registry: Standard Suites to ensure consistent terminology and behavior.[3] Compliance with AEOM standards requires applications to implement the Required Suite and appropriate functional suites to qualify as scriptable under Apple's human interface guidelines, enabling seamless integration in automated workflows. A key aspect of this compliance is type checking via the 'is' command, which verifies whether a resolved object matches a specified class before executing verbs, preventing errors in hierarchical navigation. Custom elements within the model are defined using terminology resources to align with these standards.[3]Terminology Resources
The 'aete' resource, standing for Apple Event Terminology Extension, serves as a dictionary format that applications use to define and expose their terminology for Apple Events, enabling interoperability with scripting systems like AppleScript by listing supported classes, properties, elements, and events.[22] This resource is embedded within the application's bundle and is queried by scripting components to map human-readable terms to the underlying Apple Event Object Model (AEOM) structures.[22] By providing these declarative descriptions, the 'aete' resource allows external scripts to interact with the application without requiring knowledge of low-level event codes or descriptors.[22] The structure of an 'aete' resource begins with a header containing the resource version (typically major 1, minor 0), a language code, and the number of suites, followed by entries for each suite that groups related terminology.[22] Class entries include a human-language name, a unique class ID (a four-character code), a description, and arrays detailing properties and elements; for example, a "document" class might specify properties such as "name" (type text, read-write) and "bounds" (type rectangle, read-only), along with elements like "paragraphs" that can be accessed via key forms such as index or name.[22] Event entries describe actions like "open" or "close," including the event name, class, ID, direct parameter type (e.g., file URL), expected reply type, and optional additional parameters with keywords, types, and flags indicating if they are required or enumerated.[22] Properties and parameters further include flags for read-only or read-write access, singular or plural forms, and descriptions to aid interpretation.[22] To create or edit an 'aete' resource, developers typically use the AppleScript Software Development Kit's tools, such as the Rez compiler, to generate the resource file from a textual description, or resource editors like ResEdit for manual modifications.[22] The AppleScript Editor application allows viewing and testing the resulting terminology by opening the application's dictionary, which displays the parsed 'aete' content for validation.[23] Once finalized, the resource is compiled into the application's resource fork or bundle using Rez, ensuring one 'aete' resource per application or module for comprehensive terminology exposure.[22] Best practices for defining 'aete' resources emphasize clarity and consistency to enhance scriptability: use plural forms for container classes (e.g., "paragraphs" instead of "paragraph" when referring to collections) to align with natural language patterns in AppleScript.[22] Including synonyms for properties (e.g., "point size" alongside the code 'ptsz' for font size) improves accessibility for scripters unfamiliar with specific terms.[22] Developers should avoid redefining standard suite terms to prevent conflicts and ensure unique, descriptive names for custom elements to maintain interoperability across applications.[22]Integration and Scripting
With AppleScript
Apple events form the foundational mechanism for AppleScript, allowing scripts to communicate commands and data between applications on macOS. AppleScript, as a high-level scripting language, translates its natural-language-like syntax into low-level Apple events that are dispatched via the Apple Event Manager. This integration enables users to automate workflows by directing applications to perform actions such as opening documents or querying system information, without needing to write code in lower-level languages like C or Objective-C.[8] In AppleScript, commands are mapped directly to Apple events through the application's scripting dictionary, which defines terminology in a structured format like Apple's SDEF (Scripting Definition) files. For instance, the "tell application" construct specifies the target application by setting the event's destination address, while verbs such as "get," "set," or "duplicate" correspond to specific Apple event selectors (four-character codes like 'getd' for retrieval). Object specifiers in the script, such as "first paragraph of document 1," are converted into Apple event descriptors that precisely identify elements within the target application, leveraging the Apple Event Object Model for hierarchical object addressing. This mapping ensures that AppleScript's readable syntax abstracts the binary structure of Apple events, including parameters and return values.[24][25] AppleScript operates as an Open Scripting Architecture (OSA) language, where the AppleScript component—located in /System/Library/Components/AppleScript.component—handles script execution by interfacing with the Apple Event Manager to send and receive events. During runtime, the OSA framework compiles AppleScript statements into event packets, which are then transmitted to target applications for processing. This architecture supports both local and remote interapplication communication, with the Apple Event Manager managing the dispatch and reply cycles.[26][8] Tell blocks in AppleScript establish the context for command targeting, nesting to refine object references and ensuring events are routed correctly. For example, a script might usetell application "Finder" to tell folder "Documents" to count files, which builds a descriptor chain for the nested object. Coercion in this context automatically converts data types between AppleScript classes and Apple event descriptors—for instance, transforming a string into a file reference—to facilitate seamless parameter passing and result handling.[27][24]
Since macOS Mojave (10.14), sending Apple events from applications or scripts, including AppleScript applets, requires explicit user approval in System Settings > Privacy & Security > Automation. Users must grant permission for the script or app to control specific target applications, enhancing privacy but adding a setup step for automation.[28]
Despite its power, AppleScript's reliance on Apple events introduces limitations, primarily due to the synchronous processing model of the Apple Event Manager. Events block the calling script until a reply is received, which can lead to unresponsive interfaces during long operations. Apple Events and AppleScript remain supported in macOS Sequoia (15) and later as of November 2025, with no announced deprecation. Error propagation is managed through AppleScript's try and on error blocks, which catch exceptions like unsupported commands (e.g., error -1728 for unknown events) and allow graceful recovery, such as displaying user messages for cancellations (error -128).[27][8]
Scripting Bridge Framework
The Scripting Bridge Framework, introduced in macOS 10.5 Leopard in 2007, enables developers to send Apple events to scriptable applications using standard Objective-C syntax, creating proxy objects that represent the application's scripting interface.[29] This framework leverages the SBApplication protocol, which defines methods for connecting to applications and invoking their commands and properties as Objective-C instances. By dynamically generating Objective-C classes from an application's scripting definition, it abstracts the underlying Apple event descriptors, allowing seamless interaction without manual handling of low-level event structures.[30] To use the framework, developers first generate header files from an application's Apple event terminology resources (AETE) using thesdef tool to extract the scripting definition, followed by the sdp utility to produce Objective-C bindings.[30] For example, to interact with the Music app (formerly iTunes), one might run sdef /System/Applications/Music.app | sdp -fh --basename Music to create the necessary headers, then instantiate the application proxy and invoke methods such as [music openDocument:@"path/to/file"], which automatically packages the request into an Apple event and unpacks the response.[30] The framework supports lazy evaluation, where Apple events are sent only when properties or methods are accessed, optimizing performance by deferring unnecessary communications.[30]
Since macOS Mojave (10.14), applications using Scripting Bridge to send Apple events require user permission in System Settings > Privacy & Security > Automation, or appropriate entitlements like com.apple.security.automation.apple-events for sandboxed apps. Scripting Bridge remains supported in macOS Sequoia (15) and later as of November 2025.[28][29]
While natively designed for Objective-C integration within Cocoa applications, Scripting Bridge extends to other languages through bridges like PyObjC for Python, allowing similar proxy-based scripting in those environments.[31] Historical support included now-deprecated bridges like MacRuby for Ruby. In Python via PyObjC, for instance, a developer can connect to Music and access its current track with code like Music = SBApplication.applicationWithBundleIdentifier_("com.apple.Music"); print(Music.currentTrack().name()).[30]
Key advantages of Scripting Bridge include enhanced type safety through generated headers that enforce data types for properties and parameters, runtime introspection of application capabilities via the proxy objects, and elimination of AppleScript's parsing overhead by directly bridging to the Apple event layer.[31] This makes it a code-oriented alternative to higher-level AppleScript integration, suitable for developers embedding automation in native applications without relying on external scripting engines.[29]
Modern Usage and Alternatives
Support in Current macOS
Apple Events maintain full compatibility in macOS 15 Sequoia, released in 2024, where they continue to serve as the foundational mechanism for interprocess communication and scripting integration.[2] This support extends to macOS 26 Tahoe, released on September 15, 2025, with no reported alterations to the Apple Event Manager's core functionality, ensuring seamless operation for existing implementations.[32] Backward compatibility remains robust for legacy applications through frameworks like Cocoa, allowing older software to send and receive events without modification in the 64-bit runtime environment.[33] Within the macOS ecosystem, Apple Events underpin key system services, such as Finder automation for file operations and workflow tasks.[13] They are essential for AppleScript functionality in built-in applications, including Mail for message handling and Photos for media organization, enabling users to automate routine interactions via scripting. Performance enhancements in recent macOS versions optimize Apple Events within the 64-bit runtime, reducing latency for event dispatching and improving reliability in multi-threaded applications.[32] Integration with Swift is facilitated through bridging mechanisms like Scripting Bridge, which exposes Apple Events as accessible APIs for modern development. As of November 2025, no major updates to Apple Events have been announced in macOS 26 Tahoe, preserving their role for scripting stability even as new features like Apple Intelligence are introduced, prioritizing continuity for developers and users reliant on automation.[34]Deprecation and Replacements
Apple Events, while still supported in macOS as of 2025, are regarded as a legacy interprocess communication mechanism and are discouraged for new application development. The introduction of mandatory app sandboxing in macOS 10.7 Lion imposed restrictions on Apple Events, requiring temporary exception entitlements (such ascom.apple.security.temporary-exception.apple-events) to enable sending events from sandboxed apps, which undermines the sandbox's isolation benefits and is not recommended by Apple for contemporary designs.[35] Security enhancements have further limited their utility, with remote Apple Events disabled by default since early macOS versions to mitigate risks of unauthorized network-based access; enabling this feature demands explicit user configuration in System Settings under Sharing, and it is advised against in security hardening guidelines.
In place of Apple Events, developers are directed to use XPC services for secure local interprocess communication, offering lightweight, launchd-managed helpers that isolate tasks and prevent crashes from propagating across processes.[4] For more structured interactions, NSXPCConnection provides an Objective-C and Swift-friendly interface atop XPC, enabling distributed object proxies with automatic serialization and error handling. Grand Central Dispatch integrates seamlessly with these for efficient concurrency management in multi-process scenarios, replacing ad-hoc event dispatching with queue-based task execution.
Transitioning legacy Apple Event code involves mapping event suites to XPC protocols or entitlements-secured interfaces, often simplifying to URL schemes for basic app-to-app invocation where full IPC is unnecessary. Modern tools like Swift's async/await facilitate non-blocking alternatives to traditional event replies, streamlining scripting and automation flows. AppleScript continues to serve simple automation needs atop Apple Events but pairs best with XPC for scalable, secure extensions.
Apple Events will likely persist for backward compatibility with existing software, yet the Apple Silicon transition and ongoing emphasis on hardened runtime and sandboxing prioritize secure alternatives like XPC to align with evolving privacy and stability requirements.[36]