| Authors: | Pete Brunet
Brett Clippingdale Catherine Laws Peter Parente Larry Weiss |
|---|---|
| Date: | 2007-06-04 |
| Revision: | 917 |
| Status: | final |
| Copyright: | Copyright © 2006, 2007 IBM Corporation under the BSD License |
| Source: | http://svn.gnome.org/svn/lsr/trunk/doc/workbook |
Abstract
This workbook details the architecture of the Linux Screen Reader (LSR). Each section of this document explains the purpose, relationships, activities, and terminology of an important component in LSR. Details about component implementation and user interaction are omitted from this document, though links to other relevant references are provided when possible.
The LSR system consists of three conceptual units. The engine is responsible for services such as receiving and dispatching events, providing access to information about widgets on the desktop, managing component references, and persisting data across program runs. User interface elements (UIEs) plug into the engine in order to process events, define input commands, generate output, and show dialogs to the user. The registrar connects extensions to the engine by loading them from disk, instantiating them, hooking them to appropriate engine components, and unloading them on demand.
The following figure depicts the basic relationships among the components of the engine, extensions, and registrar. Many details are omitted for brevity.
At the heart of LSR is the AccessEngine, a message pump that receives events from a desktop accessibility architecture, generates internal events abstracted away from the specifics of the platform, and dispatches the internal events for processing by extensions. The functionality of the AccessEngine is split across five manager components. The EventManager is responsible for the queuing and dispatch of both raw accessibility events and internal events. The ViewManager adapts accessible objects to stable, internal interfaces for easier traversal and querying. The TierManager dispatches internal events to scripts associated with a running desktop application. The DeviceManager delivers output to and generates internal input events from registered output and input devices respectively. Finally, the SettingsManager saves and loads settings to and from persistent storage.
Each manager relies on a number of supporting components to fulfill its duties. The EventManager uses pyLinAcc to listen for raw desktop accessibility events. It also relies on the AEEvents to wrap raw events in platform agnostic objects. The ViewManager uses a number of Adapters to unify access to information about accessible widgets on the desktop and defines Walkers for traversing the accessibility hierarchy. The TierManager maintains a list of Tiers representing running applications. Tiers, in turn, maintain independent collections of script extensions responsible for responding to events from their associated applications. All components in a Tier have access to the TaskTools API, a collection of convenience methods for script writers.
References to specific elements of the desktop are passed among all major components of the system. The concept of a point of regard (POR) is used to refer to a specific character, in a specific item, in a specific accessible widget.
Extensions to the engine are termed user interface elements because they define some aspect of the user experience. There are currently five types of UIEs. Perks are scripts which respond to events in an application. AEInput and AEOutput devices provide Perks with access to input gestures from the user and conduits for sending arbitrary output. AEChoosers engage the user in dialogs for lengthy information not easily entered through simple input gestures. AEMonitors show or log information about the internal processes of LSR to aid developers in debugging their extensions.
The UIRegistrar is the link between the LSR engine and its extensions. This component maintains a list of installed UIEs, groups UIEs into profiles defining a complete user interface, and dynamically loads UIEs at times specified in the active profile (e.g. when LSR starts, when a particular application starts, when any application starts).
The LSR architecture is implemented using features available in version 2.4 of the Python programming language. At present, the entire code base is purely Python, although C extensions may be added in the future. All components described in this workbook are realized as Python classes spread across a number of packages and modules. The UIRegistrar dynamically loads Python modulescontaining UIEs at runtime.
The LSR source code is documented using Python docstrings formatted according to epydoc syntax and grammar. Links to HTML documentation generated by the epydoc parser from the source code are provided throughout this guide.
Purpose
Description
The AccessEngine component is instantiated by a startup script. On creation, the AccessEngine component creates one instance of each of the SettingsManager, EventManager, ViewManager, TierManager, and DeviceManager components. After initializing its managers, the AccessEngine enters the system message loop responsible for dispatching raw accessibility events received from pyLinAcc and signaling components on requested timed intervals. The message loop continues until program termination. After leaving the message loop, the AccessEngine signals the managers about the impending shutdown.
Source
Purpose
Description
When created by the AccessEngine, the EventManager immediately requests to be signaled on two timed intervals. On the first signal, the EventManager dispatches raw accessibility events received from pyLinAcc to the ViewManager. On the second signal, the EventManager executes AEEvents posted by the ViewManager and DeviceManager.
The EventManager also loads AEMonitor extensions written to observe raw accessibility events. It sends information about raw events to these monitors as the events are dispatched.
Source
Purpose
Description
The pyLinAcc component creates a connection to the AT-SPI registry daemon when it is initialized. The EventManager uses the pyLinAcc event sub-components to register for raw accessibility events when the system starts. pyLinAcc notifies the EventManager of all events of interest thereafter.
pyLinAcc also "mixes" additional behavior into the AT-SPI class definitions during initialization. This "mixin" code does automatic reference counting on all accessibles and adds convenience methods such as searching for an accessible matching a given boolean expression.
Portability
The pyLinAcc package is specific to AT-SPI. This component needs to be replaced if the engine is ported to a platform using a different accessibility architecture.
Important
pyLinAcc is deprecated. pyatspi should be substituted.
Source
Purpose
Adapters create AEEvents in response to raw accessibility events dispatched by pyLinAcc to the ViewManager. The ViewManager posts these AEEvents to the EventManager for later execution. The EventManager executes these AEEvents, which in turn call methods in the ViewManager and TierManager. The information carried by AEEvents is ultimately delivered to one or more Tasks registered to observe it.
AEEvents are defined as occuring on one of three mutually exclusive layers. Events on the focus layer originate from the POR that had the application focus when the event was generated. Events on the tier layer originate from a POR in an application that was active when the event was generated. Events on the background layer originate from a POR in an application that was inactive when the event was generated. Tasks can register to receive AEEvents on any one or more of these layer.
The following are the defined AEEvents:
Source
Purpose
Description
When created by the AccessEngine, the ViewManager registers to receive raw accessibility events of interest from the EventManager. When an event is received, the ViewManager dispatches it to an Adapter keyed to the type of accessible that generated the event. Any AEEvents generated by that Adapter in response to the raw event are posted back to the EventManager.
An initial determination is made by the ViewManager as to the layer of AEEvents generated in response to raw events. If a raw event originated from an accessible having the focus or an item within an accessible having the focus, the AEEvents are set to the focus layer. All other events are marked as background layer at this stage. (See the AEEvent section for a definition of layer.)
Source
Purpose
Description
The concept of a POR is at the heart of how the nengine maintains context for system events and user interaction. A POR consists of three pieces of information: an accessible object, an item offset, and a character offset:
When a POR contains an accessible but no item offset, it refers to the accessible itself, regardless of whether it contains items. When a POR contains an accessible and an item offset, it refers to the particular item at the given offset in the accessible container. When the character offset is non-zero, it refers to a single character within either the accessible or the item within the accessible.
Important
These definitions are specific to LSR and have nothing to do with the platform accessibility architecture. For instance, the definition of an accessible in the GNOME AT-SPI architecture as an application widget or part of a widget differs from the definition used in LSR.
Portability
PORs are platform independent. Any object may be stored in the accessible slot while the item and character offsets are simple integers. How and when the last two slots are used across platforms may vary, but the structure itself will not. It is the responsibility of the Adapters to populate and interpret the fields of a POR consistently on a given platform.
Source
On startup, all available Adapters are registered with a central dispatcher. Each Adapter is registered under the interfaces it provide. When the ViewManager, a Walker, or a TaskTools method wishes to wrap an accessible or POR in a particular interface, the Adapter dispatcher selects an appropriate Adapter based on the requested interface and preconditions defined by the Adapter itself. If no Adapter precondition is satisfied, a default Adapter is selected for use instead.
The engine defines the following interfaces:
Perks never use Adapters directly. Instead, Perks call TaskTools methods which act on PORs using available Adapters.
Portability
Adapters are written to target specific accessibility APIs. A set of AT-SPI Adapters for Linux will not port to Windows, for example. However, new Adapters for MSAA, IAccessible2, and other APIs could be written. Adding new adapters increases the number of platforms on which the TaskTools will work without requiring a change in Perks.
Source
Purpose
Description
A Walker is created by TaskTools to retrieve the next, previous, parent, first, or last POR given a starting reference POR. The fetched POR points to an accessible and/or item having the specified relationship to the reference and based on the properties and implementation of the Walker.
Two walker implementations are provided in the core. The AccessibleWalker iterates over all parent-child relationships in the accessible hierarchy given a starting POR. The definition of an item is ignored by this Walker.
The AccessibleItemWalker traverses accessibles and their items given a starting POR in the accessible hierarchy. It can be set to navigate over:
The walk order of accessibles and items is best defined as an in-order traversal of the accessible hierarchy. The implementation is actually more complex, though, to account for embedded items in hypertext. The following diagrams depict the forward and backward AccessibleItemWalker state machines:
Figure: The forward walk state machine. Circles indicate methods invoked on the AccessibleItemWalker. Squares indicated adapter methods invoked during processing.
Figure: The backward walk state machine. Circles indicate methods invoked on the AccessibleItemWalker. Squares indicated adapter methods invoked during processing.
Other Walkers can be defined to traverse the hierarchy in other orders and manners. For instance, a DocumentWalker might traverse text following text flow relationships instead of parent-child connections. Similarly, a VisibleWalker might respect the visual layout of a window.
The Walkers use the IAccessibleNav and IItemNav interfaces to walk through widgets and items in the accessible hierarchy. Appropriate Adapters are selected for use based on the type of accessible currently being traversed. The definition of an item is determined by the Adapter selected. In a text accessible, a line is the default definition of an item. In a tree, list, or table, an item is a cell at a row/column intersection. In simple accessibles, there is only one item: the accessible itself.
Source
Purpose
Description
The TierManager creates a Tier when it receives an AEEvent indicating a new application has started or has been detected for the first time. The TierManager queries the UIRegistrar for all Perks associated with that application and pushes them onto a Tier. Thereafter, the TierManager dispatches AEEvents executed by the EventManager to the Tier representing the application containing the origin of the event. For example, events originating in Nautilus are forwarded to Perks in the Tier representing the Nautilus application. There is a one-to-one correspondence between Tiers and running instances of applications.
The layer of the dispatched AEEvent is fully determined by the TierManager. Focus layer events are left alone: the ViewManager has already fully determined the layer. Background layer events are promoted to the tier layer if they originated in the active Tier. The layer of an AEEvent determines which Tier will handle it. The active Tier (i.e. the last one activated by a ViewChange event) handles all focus and tier layer events. Background events are dispatched to the Tier representing the application in which the event occurred, if it exists. Events without a matching Tier are discarded.
The TierManager also loads AEMonitor extensions written to observe the processing of AEEvents by Tasks. It sends information about Tasks both as they begin and complete execution.
Source
Purpose
Description
A Tier is created by the TierManager when a desktop application window is first activated. The TierManager dispatches AEEvents to a Tier for processing by its registered Perks and Tasks.
A Tier iterates from top to bottom over its Perks looking for Tasks to execute in response to a given AEEvent. Before executing any Tasks within a Perk, the Tier provides the TaskTools with important references to other components so that its methods may operate properly.
A Tier also executes Tasks invoked by name by other Perks and Tasks. When invoking a Task by name, a Tier first determines if other Tasks are chained to it so that they may execute before, after, or around the named Task. As with AEEvents, the Tier initializes the TaskTools before executing any and all Tasks.
The value returned from Task execution indicates whether Task execution should continue or not for the current event or chain. If the return value is false, the Tier invokes a special update housekeeping method on all remaining Tasks instead of executing them.
Source
Purpose
Description
Perks and Tasks call TaskTool methods during their execution. Some methods use the available Adapters to get and manipulate accessible widgets on the desktop. Other methods contact the DeviceManager to communicate with and configure input and output devices. Still others invoke methods on the UIRegistrar to manage user interface elements.
The TaskTools methods are pre-configured by a Tier before the execution of a Perk or Task. The TaskTools are provided with important references, such as the parent Tier, the POR associated with an event originating on the desktop, all managers, and so on.
Source
Purpose
Description
When created by the AccessEngine, the DeviceManager queries the UIRegistrar for registered AEInput and AEOutput devices. The DeviceManager attempts to initialize the devices in the order specified by the registrar. Only the first device providing at least one unique I/O capability is initialized. For instance, only the first speech device is initialized even if others exist in the UIRegistrar load order. However, one speech and one Braille device, though both implementing AEOutput, may both be initialized by the DeviceManager.
The DeviceManager sets itself as a listener on all initialized devices. The DeviceManager posts AEEvents to the EventManager in response to callbacks from these devices.
The DeviceManager also loads AEMonitor extensions written to observe input and output streams. All information sent to one or more output devices is logged. In addition, all gestures received from an input device are logged.
Source
Purpose
Description
When created by the AccessEngine, the SettingsManager opens the settings repository for the profile under which the AccessEngine was initialized. The SettingsManager holds the repository open to fulfill load and save requests of AEState objects at runtime. When the AccessEngine terminates, the SettingsManager persists all settings and closes the repository.
The SettingsManager maintains an in-memory cache of all AEState objects it loads for Perks. This cache is used to ensure a single AEState object is shared across all instances of a given Perk class in one or more Tiers.
Portability
The SettingsManager currently persisted all setting names and values to Python pickle files. These files are portable to other platforms.
Source
Purpose
Description
The AEState component itself performs no actions. It is an interface that an state class must implement to support configuration by the user and persistence on disk.
A state object that implements AEState can be used to generate configuration dialogs and enable the persistence of data by the SettingsManager. Perks may define classes that implement AEState to support the changing and persistence of Perk specific settings. AEInput and AEOutput devices may do the same.
Source
Purpose
Activity
The UIRegistrar creates an on-disk repository for managing Perks, AEInput and AEOutput devices, AEChooser dialogs, and AEMonitors when LSR is first run or upgraded. The LSR startup script installs the UIEs packaged with LSR, creates all default profiles, and configures the profiles to load appropriate UIEs.
The UIRegistrar is contacted by the various managers in order to load UIEs at runtime. The EventManager, TierManager, and DeviceManager all request references to AEMonitors. The DeviceManager requests references to AEInput and AEOutput devices registered to load at startup. The TierManager contacts the UIRegistrar whenever a new Tier is created in order to load its Perks.
Source
Purpose
Terminology
Purpose
Description
A UIE that implements Perk is responsible for responding to events from the desktop and other LSR components. The response from the collection of active Perks defines the user interface.
Perks are registered with the UIRegistrar to be loaded by the TierManager when any Tier is created or when a particular Tier is created. A Perk may also choose to load other Perks on demand using the TaskTools.
A Perk is initialized after it is pushed onto a Tier. During initialization, a Perk may perform any number of actions, such as:
A Perk provides an execution context with variables shared across all Tasks registered by the Perk. Each Perk instance is independent of copies in other Tiers. However, all instances of a Perk share access to the AEState object for that Perk.
Source
Purpose
Description
A Task is executed by the Tier containing the Perk that registered it. Before executing a Task, the Tier configures the TaskTools with information about the current POR, Perk settings, and Tier state. During execution, the Task uses the TaskTools to query accessibility information, give output, change the state of the system, manipulate how other Tasks will execute, and so forth.
A Perk typically registers Tasks during its initialization as handlers for AEEvents. The following Tasks are defined in correspondence with the available AEEvents:
Event handling Tasks are executed in the order defined by the Perk stack. Perks at the top of the stack are typically specific to an application and handle events first. More general Perks are located at the bottom of the stack and handle events last.
A Task may be registered to handle AEEvents on any combination of the focus, tier, and background layers. For instance, the GaimPerk registers a CaretTask for events on the tier and focus layers. The effect of this registration is that incoming messages are announced whether the message history has the focus or not as long as one of the gaim windows is active (i.e. when it is not in the background).
A Perk may also register Tasks with names unique across an entire Tier. Named Tasks may be referenced by any Perk within the Tier and may be associated with input gestures from an AEInput device. Tasks in other Perks may invoke a Task in the same Tier by its name.
Named Tasks may also be chained to other named Tasks. A chained Task may execute before, after, or around its anchor, the Task to which it is chained. A Task chained before its anchor has the ability to prevent later Tasks in the chain from executing. A Task chained after has the ability to modify the return value from earlier Tasks. A Task chained around the anchor has the ability to manipulate both the parameters and return value given to the anchor, or to prevent the anchor from running at all.
Source
Terminology
Purpose
Description
A UIE that implements AEInput is responsible for monitoring and reporting the occurrence of input gestures. Each device decides what constitutes a valid gesture for its purposes. In general, a gesture consists of a series of actions performed by the user that may indicate a command or query.
An input device that implements AEInput is managed by the DeviceManager. A Perk registers Tasks to receive notification of input gestures performed on the device. The registered Tasks are notified using AEEvents when an input gesture is recognized.
Source
Terminology
Purpose
Description
UIE that implements AEOutput is responsible for presenting output to the user. Each device decides how to render its output according to the capabilities of the device driver and hardware, the presentation settings defined by the user, and any styles applied by Perks.
An output device that implements AEOutput is managed by the DeviceManager. A Perk sends output messages to one or more devices using the TaskTools. The TaskTools may tag any output message with metadata describing the message. A devices uses this information to determine how the information should be styled when output. For instance, the output message "button" tagged as being a widget "role" might be styled in a different voice on a text to speech engine, routed to status cells on a Braille display, or affect the zoom region bounds on a magnifier.
Source
Terminology
Purpose
Description
A UIE that implements AEChooser is loaded by a Task using TaskTools methods. The chooser may signal the Task at any time. The Task may choose to act on or ignore any signal it receives. For instance, a search chooser may signal its final search string for a Task to process.
Source
Terminology
Purpose
Description
A UIE that implements AEMonitor is loaded by the DeviceManager, EventManager, or TierManager. Once loaded, the monitor is sent information about the processes occurring in that manager. The monitor may, for example, log this information to a file on disk, to a console window, or even to a GUI dialog.
Source
2007-06-04 Peter Parente <pparent@us.ibm.com>
2007-01-25 Peter Parente <pparent@us.ibm.com>
2007-01-24 Peter Parente <pparent@us.ibm.com>
2007-01-21 Peter Parente <pparent@us.ibm.com>
2006-09-29 Peter Parente <pparent@us.ibm.com>
2006-06-01 Peter Parente <pparent@us.ibm.com>
2006-03-17 Peter Parente <pparent@us.ibm.com>