Building Custom Accessible Widgets

This section is an introduction to building custom accessible widgets for a Linux GNOME application using ATK. There are basically two different ways to create a custom widget for a GNOME application:

  1. Start with a GTK widget class and override gtk_widget_get_accessible in your widget's AtkObject implementation. Assess which ATK interfaces (including attributes and events) can be inherited versus overridden from the parent widget class.

  2. Create an AtkObjectFactoryClass which overrides create_accessible and get_accessible_type. Register the AtkObject factory type usingatk_registry_set_factory_type. Determine which ATK interfaces a custom widget should implement based on the widget's features and functionality.

Note: The GAIL library is an ATK implementation libary for GTK widgets. Its source code may be helpful in understanding how to create custom ATK object implementations for custom widgets. However, if developing proprietary code, do not review GAIL or any other open source code protected by open source licenses. Violating this rule could compromise the originality of proprietary code.

Start with a GTK widget class

If creating a custom GTK widget, create an AtkObject subclass which overrides gtk_widget_get_accessible and inherits from a "default" ATK implementation for a similar GTK widget. Decide which ATK interface methods the new widget should override and if there are additional ATK interfaces that should be supported. For example, if the custom widget is like a GTK notebook widget, determine which AtkObject, AtkSelection, AtkComponent, AtkStateSet, and AtkRelationSet method implementations in the basic widget and notebook widget classes that the new custom widget ATK implementation should inherit versus override. If additional ATK interfaces (i.e. AtkText, AtkHypertext, AtkTable, etc), methods, role, states, or events should be supported, implement those.

Create and register an ''AtkObject'' factory

If a custom widget or set of custom widgets does not have an accessible object (AtkObject) implementation in an ATK implementation library, then the developer must provide custom AtkObject implementations in a GTK module. (Note that libgail.so is a GTK module containing all the ATK implementation classes for GTK widgets.) This module should be included in the GTK_MODULES environment variable so it is loaded at runtime. Each AtkObject implementation has a corresponding accessible object factory class (AtkObjectFactoryClass). A central ATK registry links object types (GTypes) to these accessible object factories.

Each factory must be implemented as a child of class type ATK_TYPE_OBJECT_FACTORY and must implement the function create_accessible. This function must create an appropriate AtkObject. A factory can be used to create more than one type of object, in which case its create_accessible function will need to include logic to build and return the correct AtkObject.

AtkObject* atk_object_factory_create_accessible
           (AtkObjectFactory *factory, GObject *obj);

Create an AtkObjectFactoryClass with an initialization function that overrides the default create_accessible and get_accessible_type methods for an AtkObjectFactory:

static void
newatklib_new_widget_factory_class_init (AtkLibNewWidgetFactoryClass *klass)
{
  AtkObjectFactoryClass *class = ATK_OBJECT_FACTORY_CLASS (klass);
  class->create_accessible = newatklib_new_widget_factory_create_accessible;
  class->get_accessible_type = newatklib_new_widget_factory_get_accessible_type;
}

Then implement those methods in the factory class.

In the base ATK implementation class, register an ATK object factory type for each ATK object in the ATK module initializaion method:

atk_registry_set_factory_type (atk_get_default_registry(), SOME_TYPE_NEW_WIDGET,
                               newatklib_new_widget_factory_get_accessible_type());

Macros could be defined in the factory class and then used by the accessibility_module_init function in the base widget class to create and register the ATK object factory types for new widgets.

Creating an ATK object implementation class

After ensuring that every custom widget in your application has an AtkObjectFactoryClass which is registered, developers must create an ATK object implementation class for each custom widget that either overrides ATK interfaces in the parent widget class or implements all the ATK interfaces required to support the features and functionality of the custom widget.

Implement get_type plus class and instance initializer functions

As a first step, all AtkObject implementation classes (which are GObjects) must implement a get_type() function to set up class and instance initializer functions, and to indicate which ATK interfaces the ATK object implements. The class_init() function can redefine any ATK functions calls defined by the object's parent class, and can define the object class' own custom init(), notify_gtk(), and finalize() functions. A custom init() function caches data or listens to signals retrieved from a backing GTK widget. If the ATK object needs to listen to property notifications from a backing GTK widget, a notify_gtk() function is needed. A finalize() function is needed to free data when the ATK object is destroyed. Examples 5 - 12 in the "GNOME Accessibility for Developers" guide show sample implementations of all these functions.

Implement base ''AtkObject'' methods and properties

If creating a base AtkObject class for a whole set of custom widgets, or if overriding base ATK object property values (such as name, description, relations, role, and states), in a more specific AtkObject class, you need to implement functions which override the methods or set properties found in the ''AtkObject'' interface. For example, a base AtkObject class for widgets should implement AtkObject methods such as atk_object_get_description, atk_object_get_parent, atk_object_ref_relation_set, atk_object_ref_state_set, atk_object_get_index_in_parent, and atk_object_initialize. Specific ATK widget classes, such as a widget class for a radio button, which inherit from a base AtkObject class may need to implement only atk_object_initialize to set the specific widget's role property.

Parent objects should identify their child objects in the logical order in which they should be navigated via the keyboard, and child objects should report who their parent is and where they are located within the parent object. To make it possible for assistive technologies to properly navigate all objects in the correct order, it is critical for application developers to implement the following ATK interfaces and methods:

When it is not possible to indicate parent/child relationships between objects that match relationships seen visually, implement ATK_RELATION_FLOWS_TO and ATK_RELATION_FLOWS_FROM to let the AT know the logical navigation order of those objects.

The AtkObject interface provides a significant number of built-in role enumerations.

The atk_object_ref_state_set returns information about object states, for which enumerations are defined in the AtkState interface. Associate states with custom objects using AtkStateSet.

The atk_object_ref_relation_set returns an object's relationship types, which are enumerated in the ''AtkRelation'' interface. [bmgapguidegtkatk.html#_Toc412398981 Establish relationships between objects] for custom objects using the same AtkRelation, AtkRelationSet, and AtkObject methods used for defining relationships between GTK+ widgets.

Flyweight objects are AtkObjects created on the behalf of objects that aren't full-blown widgets, like cells in a treeview or table, and icons in an icon list. Their state is ATK_STATE_TRANSIENT, and they need to be generic enough to be useful in other widgets.

Two derived implementations of AtkObject are:

  1. AtkNoOpObject, which is the type of AtkObject created if an accessible object is requested for an object type for which no factory type is specified. When implementing this type of accessible object, all ATK interfaces should also be implemented. I think this just happens but application developers shouldn't do anything with this interface.

  2. ''AtkGObjectAccessible'', which should be implemented for GObjects which are not derived from GtkWidget, such as a canvas item.

Implementing ATK Subinterfaces

Custom widget developers must also decide which of the following ATK subinterfaces should be implemented for each widget to further define for an AT the specialized type of object and its features, functions, and behaviors.

AtkAction: Interactive AtkObjects (such as buttons, checkboxes, menu items, etc) should implement this interface to execute and describe an object's activations (click, press, toggle, expand, etc) and expose its key bindings, except when the user interaction is already covered by another appropriate interface. Exceptions include ''AtkEditableText'', which handles text insertion and deletion, and AtkValue, which handles the setting of values. When mouse and keyboard actions are redundant, expose only one action.

AtkComponent: All graphical user interface (GUI) objects which have screen coordinates should implement this interface to expose information about an object's size, position, and focus. A possible exception may be a text object with a transparent background that implements ''AtkText'' instead. Be sure to implement atk_component_ref_accessible_at_point and atk_component_get_extents to assist an AT in restricting their review of objects to what's visible in order to achieve better performance. A base ATK object class could implement AtkComponent, and ATK object classes which subclass the base class would inherit that implementation.

''AtkImage:'' Objects which display image or pixmap content on the screen, such as icons, buttons with icons, toolbar elements, and image viewing panes, should implement this interface to expose image descriptions (such as alternative text), size, and position.

''AtkSelection:'' UI components whose children can be selected, such as selectable lists and tree views, should implement this interface. For text selection, use the AtkText interface instead. If multiple children can be selected at the same time, set the ATK_STATE_MULTISELECTABLE state.

''AtkTable'': UI components which order child cell objects in rows and columns or present tree-structured information should implement this interface to expose row and column information (descriptions, headers, number of, selection, content at specific index) and the table caption and summary. The child objects (cells, headers, captions, summaries) implement other interfaces, such as AtkText and AtkImage, as required.

AtkValue: UI objects, such as sliders or dials, which either display and/or allow the user to specify a value from a bounded range should implement this interface for setting the current value and getting the minimum, maximum, or current value for a control. Values may be read-only.

AtkStreamableContent: UI text objects should implement this interface to provide access to a flat, streamable content view of a document. This interface is primarily useful for saving, printing, or post-processing entire documents, or for persisting alternate views of a document.

AtkText and AtkEditableText: Non-trivial objects which have non-editable text content with text attributes, are multi-line, and/or are selectable should implement the AtkText interface to expose text, character, caret, selection, range, and attribute content and information. If the text content is editable, the AtkEditableText interface should be implemented instead to expose all AtkText information as well as content which is copied, cut, pasted, inserted, and deleted. If the text is short and simple with no attributes, implement atk_object_get_name in the AtkObject interface instead.

If the text object is a document object, also implement AtkDocument (which is being updated) to indicate the document boundaries, locale, attributes, and events, plus implement all the ATK interfaces required to [GAP/AtkGuide/Atk#_Toc412398982 expose the accessibility information for each embedded object in the document]. Parent objects in a document should identify their child embedded objects in the logical order in which they should be navigated via the keyboard, and child objects in a document should report who their parent is and where they are located within the parent object using the parent and child methods in AtkObject as described above when implementing any accessible object. For example, a single paragraph may be a parent object for multiple child objects, such as images.

Remember to [bmgapguidegtkatk.html#_Toc412398981 establish relationships between objects] for form controls embedded in a document using the same AtkRelation, AtkRelationSet, and AtkObject methods used for defining relationships between GTK+ widgets.

Use the AtkSelection interface on the top-level document object to show which paragraphs have selected text, especially if selections span paragraphs or if there are multiple text selections in a document.

  • Implement AtkAction for all form controls and elements with event handlers in a document as well as the atk_action_get_keybinding method to identify access keys when defined for interactive elements.

    Identify and expose the accessible information for all types of embedded objects in documents, including images, tables, hyperlinks, paragraphs, and text controls, by implementing AtkImage, AtkTable, AtkText, AtkHypertext, and AtkHyperlink.

The AtkText interface provides a set of enumerated text attributes, but when necessary, new name-value pairs can be defined as text attributes to describe new object characteristics using atk_text_attribute_register. To set attributes for text objects, implement atk_editable_text_set_run_attributes in the AtkEditableText interface, even if the text object is read-only.

To assist an AT in restricting their review of objects to what's visible in order to achieve better performance, be sure to implement atk_text_get_character_extents, atk_text_get_offset_at_point, and atk_text_ get_bounded_ranges.

Note: To improve the efficiency of complex document navigation by assistive technologies, a new AtkCollection interface may be defined to match the new AT-SPI ''Collection'' interface sometime in the near future. For now, the AT-SPI Collection interface will be implemented in the ATK bridge to use the ATK interfaces implemented for objects embedded in complex, rich text documents. Complete implementation of ATK interfaces for embedded objects is critically important for the success of the Collection interface implementation.

''AtkHypertext''and '''AtkHyperlink''': Each UI object containing links should implement the AtkHypertext interface to provide a way to get links, their offsets, and the number of links. Each object which contains a link or set of links should also implement AtkHyperlink to provide a way to get URIs and find out information about the anchors (location, validity, is inline, is selected, how many), but the information is returned via calls to AtkHypertext. AtkHyperlink implements AtkAction for activating links.

For recommendations about which ATK interfaces, states, role, events, actions, and other accessible information and behaviors should be implemented for common types of user interface objects, refer to section [GAP/AtkGuide/UI Recommended ATK Implementations for Common UI Components].

Managing Children

There are two types of children you can have in any GUI application. One is a "live" child, created by adding a component to a container. These live children operate as separate entities and respond to events propagated by the component hierarchy.

The second type of child is drawn and managed by the parent in an effort to save system resources. Here, the parent is a "proxy" for its child. This lightweight, proxied child is usually a transient object. A typical proxied child would be a list box entry. A list box could have 100 items in it and you would not want to have the overhead of creating a live child for each item. So, proxied children are manufactured and drawn by their parent from the list boxes data as needed.

An example of this is implementation of GTK cell renderers for a list box, which is created using a GtkTreeView widget. In a GTK list box, each list entry is created through the use of a single GtkCellRenderer. The GtkTreeView widget for the list box tells the renderer where to draw, when to "appear" selected, and so on. The GtkTreeView component does not care what the cell renderer draws in it as long as the renderer does what it is told. The cell renderer does not receive focus from the windowing system, even though GtkTreeView may ask it to appear focused.

The GtkNotebook widget presents a different parent/child relationship that might best be described as a limited proxy. In the case of notebook page tabs, you know you will be dealing with a limited number of children. Here, the tabs are not actually components, but merely visual page tab elements with a reference to the component to be shown, based on the page tab selected. Because the list of elements is small, and generally persistent, it is easier to maintain a vector of accessible objects representing each page tab. When assistive technology requests an accessible child, the ATK implementation for GtkNotebook, merely goes to the internal vector of accessible page tab objects and returns the corresponding object.

The parent component should report its accessible children using atk_object_get_n_accessible_children andatk_object_ref_accessible_child.

Here are some basic rules to follow when managing children:

  • Make sure the children implement AtkObject.

  • If the children are selectable, a proxying parent should:
    • Implement AtkSelection. This is not the case when the parent does not proxy for the child.

    • The children must indicate the state ATK_STATE_SELECTED in their AtkStateSet interface implementation when selected.

  • Proxying parents managing states for their children should fire property-change events from their AtkObject interface for their children. This is very important for proxying components that manage large lists of children. Assistive technology developers would like to avoid adding ObjectEventListeners to each list entry.

  • When managing focus for a child, make sure the children are accessible via the keyboard.
  • Make sure the parent reports the children (0 through n-1) in the logical order they appear and are navigable via the keyboard.
  • Make sure all property change events are fired. If you have a child whose text changes, make sure to fire a visible-data-changed property event unless the child implements AtkText, which should fire the text_changed event.

  • All children must report who their accessible parent is. For live GTK components this is done automatically. For all custom components the parent should be the actual accessible parent.
  • Only report proxied children in accessible child count and when acquiring the accessible children. The other live children are already handled via the component count from their container.

Managing Events

The main purpose of the class AtkUtil is to provide methods for adding and removing event listeners and for inquiring about the root AtkObject of the application and the name and version of the GUI toolkit. The adding and removing of the listeners must be done in the same thread. The following event listeners can be added:

  • Focus tracker: Use atk_add_focus_tracker to provide a function that gets called when an object receives focus.

  • Global events: Use atk_add_global_event_listener to provide a function that gets called when a specific type of event occurs.

An application or toolkit that bridges to ATK needs to subclass AtkUtil and to re-implement these methods. For event notification it is necessary to manually notify each of the event listeners.

Since live children need to be available to receive events, they are are also available to fire events, such as accessible state change events, needed by an assistive technology. However, unlike live children, proxied children are usually transient and therefore an assistive technology would not be able to receive any events from them. Therefore, all accessibility events pertaining to the proxied children should be generated from the proxying parent.

Refer to section [GAP/AtkGuide/Atk2Msaa#msaaevents Object Level Events aka Signals] for a list of ATK events.

To set up event listeners for ATK objects and which functions should be called when a specified event type occurs, use AtkEventListener(), atk_add_global_event_listener, atk_add_focus_tracker, and related methods in the AtkUtil class. Object events are also known as signals in GNOME and ATK. Some new events/signals are being proposed as a result of AT-SPI 1.7 interface changes.

Examples:

  • Create an event watcher, for example in a base ATK implementation class, with the atk_add_focus_tracker() function:

      atk_focus_tracker_init (my_focus_tracker_init);
      focus_tracker_id = atk_add_focus_tracker (my_focus_tracker);

    where _my_focus_tracker() is a function with this prototype:

      static void _my_focus_tracker (AtkObject *aobject);
    • What about atk_component_add_focus_handler in AtkComponent? How is that different from the focus tracker in AtkUtil?)

  • Set up a global event listener, with atk_add_global_event_listener():

      mouse_watcher_focus_id =
         atk_add_global_event_listener(_my_global_listener,
         "Gtk:GtkWidget:enter_notify_event");

    where _my_global_listener has the prototype of a Glib GSignalEmissionHook. This example would cause the _my_global_listener() to be called whenever an enter_notify_even signal occurs on a GtkWidget object.

  • Setting up an ATK signal handler: Using the column_inserted signal as an example:

         table_column_inserted_id = g_signal_connect_closure_by_id (my_atk_obj,
         g_signal_lookup ("column_inserted", G_OBJECT_TYPE (my_atk_obj)),
         0, g_cclosure_new (G_CALLBACK (_my_table_column_inserted_func),
         NULL, NULL), FALSE);

    This will cause _my_table_column_inserted_func() to be called whenever a column_inserted signal is emitted on the AtkObject my_atk_object.

  • Connecting to or generating a signal is slightly different if the signal supports detail. The children_changed signal supports the add detail. To generate this signal with the add detail is also specified, this technique is used:

      g_signal_emit_by_name (atk_obj, "children_changed::add",
      ((row * n_cols) + column_count), NULL, NULL);

ATK implementation examples for documents

Below is a table containing HTML document samples with recommend ATK implementations.

Note: All accessible objects implement AtkObject and AtkComponent. Key: * = Embedded object character (0xfffc), used when no text from the object will be inserted in the parent AtkHypertext

Example: Paragraph with an Image in it

HTML source
  • <h1>This is a heading</h1>
    <p>
      This is a paragraph with an
      <image src="image.gif"
             alt="some image"/>
      image in it.
    </p>
    <h2>This is another heading</h2>

  • (parent AtkText, role=ATK_ROLE_HEADING,
     objattr="xhtml:role=h1",
       text-attributes="css:font-size=LARGER",
       text="This is a heading")
    (parent AtkHypertext, role=ATK_ROLE_PARAGRAPH,
     attr="xhtml:role=p"
     text="This is a paragraph with an * image in it")
      (child AtkImage, AtkHyperlink, role=ATK_ROLE_IMAGE,
       ImageDescription ="some image",
       AccessibleName = "" [the HTML title attribute,
         if present]
       hyperlink-range=[28,29])
    (parent AtkText, role=ATK_ROLE_HEADING,
       objattr="xhtml-role:h2",
       text-attributes="css:font-size=LARGE",
       text="This is another heading")

Example: Header with a break in it

HTML source
  • <p>Hey!<br>Tell me something.</p>

  • (parent AtkText, role=ATK_ROLE_PARAGRAPH, attr="xhtml:role=p",
     text="Hey!\nTell me something")

HTML source
  • <a href="http://www.google.com">Hey!
    <br>Tell me something.</a>

  • (parent AtkHyperlink, AtkText, role=ATK_ROLE_LINK
     attr="xhtml:role=a;link-type=anchor",
     text="Hey!\nTell me something",
     hyperlink-range=[depends on the containing context],
     hyperlink-URI="http://www.google.com",
     hyperlink-Object=AtkText)

Example: Two paragraphs with a horizontal line

HTML source
  • <p>Hey</p><hr/>
    <p>Tell me something</p>

  • (parent1 AtkText, role=ATK_ROLE_PARAGRAPH,
     text="Hey")
    (parent2 role=ATK_ROLE_SEPARATOR,
     [note: AtkState doesn't include ATK_STATE_VERTICAL,
           to distinguish from vsep])
    (parent3 AtkText, role=ATK_ROLE_PARAGRAPH,
     text="Tell me something")

Example: Pagragraph with an emphasis

HTML source
  • <p>
      You <em>are</em> a nice person.
    </p>

  • (parent AtkText, role=ATK_ROLE_PARAGRAPH, attr="html:role=p",
     text="You are a nice person",
     attribute run for "are", with textattr="em=true,
    css:text-style=oblique")

HTML source
  • <p>
      Here is a
      <a href="http://foo.bar.com">
        bartending site
      </a>
     .
    </p>

  • (parent AtkHypertext, role=ATK_ROLE_PARAGRAPH, attr="html:role=p"
      text="Here is a bartending site.",
      attribute run for "bartending site." with textattr="link=true,
      css:text-decoration=underline, css:color=(0,0,255)")
       (child AtkText,  AtkHyperlink,
         role=ATK_ROLE_LINK, attr="html:role=a, link-type:anchor",
         text="bartending site",
         hyperlink-indices=[10,26]
         hyperlink-URI="http://foo.bar.com")

HTML source
  • <p>
      Here is a
      <a href="http://foo.bar.com">
        <image src="beerglass.GIF"
               alt="beer glass"/>
        bartending site
      </a>
      .
    </p>

  • (parent AtkHypertext, role=ATK_ROLE_PARAGRAPH,
    attr="html:role=p" text="Here is a bartending site."
     attribute run for "bartending site." with textattr="link=true,
      css:text-decoration=underline, css:color=(0,0,255)")
       (child AtkHypertext, AtkHyperlink,
         role=ATK_ROLE_LINK,
         text="*bartending site"
               hypertext-indices=[10,26],
    [not sure if we need to dup textattrs here, or add them to defaulttextattrs],
         hypertext-URI="http://foo.bar.com")
             (grandchild AtkImage, AtkHyperlink
               role=ATK_ROLE_IMAGE, attr="html:role=img,
               link-type=image"
               AccName/ImageDescription="beer glass",
               hyperlink-indices=[0,0]
            hyperlink-URI="beerglass.GIF")
    [don't know if the URIs should always be fully specified, or if omitting the base URI is OK]

Example: BLAH with a break in it

HTML source
  • <p>
      Here is a
      <image src="beerglass.GIF"
             alt="beer glass"/>
      <a href="http://foo.bar.com">
        bartending site
      </a>
      .
    </p>

  • (parent AtkHypertext, role=ATK_ROLE_PARAGRAPH, attr="html:role=p",
      text="Here is a *bartending site."}
       {child AtkImage, AtkHyperlink,
         role=ATK_ROLE_IMAGE, attr="html:role=img, link-type=image"
         AccName/ImageDescription="beer glass",
         hyperlink-indices=[10,10]
         hyperlink-URI="beerglass.GIF")
       (child AtkText, AtkHyperlink, AtkAction,
        AtkHypertext, role=ATK_ROLE_LINK,
         action-names="activate", [others?]
         attr="html:role=a, link-type=anchor"
         text="bartending site",
         textattr=[as in above examples]
         hypertext-indices=[10,26],
         hypertext-URI="http://foo.bar.com")

Example: image map

HTML source
  • <p>
      <IMG SRC="sitemap.gif"
           ALT="Site map"
           USEMAP="#mymap"></p>
      <MAP name="htmlcat_ibmgapguidecustom.html_mymap" title="site map">
        <AREA href="#htmlcat_1.html" ALT="Bar"
              COORDS="5,5,95,195">
        <AREA href="#htmlcat_2.html" ALT="Baz"
              COORDS="105,5,195,195">
        <AREA href="#htmlcat_3.html" ALT="Fu"
              COORDS="205,5,295,195">
      </MAP>
    </p>

  • (parent AtkHypertext, role=ATK_ROLE_PARAGRAPH,
     text="*")
      (child AtkImage, AtkHypertext,
       role=ATK_ROLE_IMAGE_MAP,
       attr="html:role=map",
       hyperlink-URI="sitemap.gif",
       ImageBounds=[entire map area]
       AccName and ImageDescription="Site map"}
        (grandchild AtkHyperlink, AtkAction,
         action-names="click", role=ATK_ROLE_LINK,
         attr="html:role=area", hyperlink-URI="1.html", name="htmlcat_ibmgapguidecustom.html_Bar")
        (grandchild AtkHyperlink, AtkAction,
         action-names="click", role=ATK_ROLE_LINK,
         attr="html:role=area", hyperlink-URI="2.html", name="htmlcat_ibmgapguidecustom.html_Baz")
        (grandchild AtkHyperlink, AtkAction,
         action-names="click", role=ATK_ROLE_LINK,
         attr="html:role=area", hyperlink-URI="3.html", name="htmlcat_ibmgapguidecustom.html_Fu")
    [note that the component bounds of the areas correspond to their rectangular bounding boxes]

Example: bulleted list

HTML source
  • <ul>
      <li>This is a list item.</li>
      <li>This is another list item.</li>
    </ul>

  • (parent AtkObject, role=ATK_ROLE_LIST,
       attr="css:list-style-type=disc")
      (child AtkText, role=ATK_ROLE_LIST_ITEM,
       text="This is a list item.",
       attribute run "static" first 2 chars)
      (child AtkText, role=ATK_ROLE_LIST_ITEM,
       text="This is another list item.",
       attribute run "static" first 2 chars)
    [we should be able to support list-style=image, and "list-style-image=URL()", etc. this way.
    In the above example, it's not clear whether the bullet should be a unicode char
    or just omitted and implied by the list style..
    my guess is the latter (i.e. bullets don't appear in the text)]

Example: numbered list

HTML source
  • <ol>
      <li>This is a list item.</li>
      <li>This is another list item.</li>
    </ol>

(parent AtkObject, role=ATK_ROLE_LIST,
   attr="html:role=ol, css:list-style-type:decimal")
  (child AtkText, role=ATK_ROLE_LIST_ITEM,
   text="1. This is a list item.",
   attribute run "static" first 3 chars)
  (child AtkText, role=ATK_ROLE_LIST_ITEM,
   text="2. This is another list item.",
    attribute run "static" first 3 chars)
[we should clearly define a text attribute which means "this text is
not explicit in the content, but was added by the presentation/user agent. I
believe MSAA/IE uses "static" ?]

Example: nested bulleted lists

HTML source
  • <ul>
      <li>
        This is a list item.
        <ul>
          <li>Nested item 1</li>
          <li>Nested item 2</li>
        </ul>
      </li>
      <li>This is another list item.</li>
    </ul>

  • (parent AtkObject, role=ATK_ROLE_LIST,
       attr="html:role=ul, css:list-style-type=disc")
      (child AtkHypertext, role=ATK_ROLE_LIST_ITEM,
       text="This is a list item.*"}
         (grandchild AtkObject, AtkHyperlink, role=ATK_ROLE_LIST,
          attr="html:role=ul, css:list-style-type=circle,
          link-type=child",
          hyperlink-indices=[20,20],
          hyperlink-URI="",
    [Hmm, degenerate case here...] )
            (great-grandchild AtkText, role=ATK_ROLE_LIST_ITEM,
              attr="html:role=li" text="Nested item 1")
            (great-grandchild AtkText, role=ATK_ROLE_LIST_ITEM,
               attr="html:role=li" text="Nested item 2")
       (child AtkText, role=ATK_ROLE_LIST_ITEM,
        text="This is another list item.")
    [Note that unlike user interface ATK_ROLE_LIST objects, these lists don't
    implement AtkSelection, and the list items' AtkStateSets do not include
    ATK_STATE_SELECTABLE. There is a question here as to whether <ul> and <ol> elements
    should always implement AtkText or not. I think it would be better if they did not, unless they had
    non-empty text content, but this may prove impractical.]

Example: form with a text area

HTML source
  • <form>
      <div>
        <label for="self"/>
          Tell me a little more:
        </label>
      </div>
      <div>
        <textarea>
          I am a monkey with a long
          tail. I like to swing from
          trees and eat bananas. I've
          recently taken up typing
          and plan to write my memoirs.
        </textarea>
      </div>
    </form>

  • (parent AtkObject, role=ATK_ROLE_FORM, text="")
      (child1 AtkObject, role=ATK_ROLE_SECTION?
    [or should we use ATK_ROLE_PANE?]
    )
         (grandchild AtkText,
          role=ATK_ROLE_LABEL,
          ATK_RELATION_LABEL_FOR=child2,
          text="Tell me a little more:")
      (child2 role=ATK_ROLE_SECTION?)
        (grandchild AtkEditableText,
         AtkRelation, AtkStateSet, AtkAction,
         ATK_ROLE_ENTRY,
         text="I am a monkey with ..."),
         ATK_RELATION_LABELLED_BY=child1,
         STATE_MULTILINE,
         STATE_REQUIRED allowed)
    [ attribute run over the portion of the text scrolled into view?
    CONTROLLER_FOR/CONTROLLED_BY for the scrollbar/viewport?
    Alternative would be to treat all the text content as though it were visible, but that's no good
    for magnifiers and ATs for the mobility-impaired. Probably the textarea needs to be expanded somewhat, or at least fitted with AtkActions for scrolling
    plus text attribution for determining what parts of the text are
    currently scrolled into view, without the AT client having to resort to bounds checking in the
    "screen review" fashion. This is, however, a general problem with multiline text in viewports.
    The relatively new AtkText getBoundedRanges API reduces the pain somewhat since you can
    feed it the AtkComponent bounds and it will give you back the visible text.]

Example: form with checkbox

HTML source
  • <form aaa:describedby="checkhelp">
      <p>
        <span
         x2:role="wairole:description"
         id="checkhelp">
            Check one or more:
        </span>
        <input id="cb1" type="checkbox"/>
        <label for="cb1">Red</label>
        <input id="cb2" type="checkbox"/>
        <label for="cb2">Blue</label>
        <input id="cb3" type="checkbox"/>
        <label for="cb3">Green</label>
      </p>
    </form>

  • (parent AtkObject,
     role=ATK_ROLE_FORM,
     attr="html:role=form",
     RELATION_DESCRIBED_BY=grandchild1,
     text="?")
      (child AtkText,
       role=ATK_ROLE_PARAGRAPH, attr="html:role=p", text="")
        (grandchild1 AtkText,
         role=ATK_ROLE_LABEL,
         RELATION_DESCRIPTION_FOR=parent,
         attr="html:role=wairole:description")
         text="Check one or more:"}
        (grandchild2 AtkAction,
         AtkStateSet, role=ATK_ROLE_CHECK_BOX,
         attr="html:role=input",
    [and same with other elements, expose html:role]
    [note also that these objects do NOT have accessible names, because they are labelled;
    accessible-name would presumably come from the HTML title attribute or other attribute.
    This is mainly to make it easier for ATs to avoid highly redundant speech in these cases.]
         ATK_RELATION_LABELLED_BY=grandchild3)
        (grandchild3 AtkText,
         role=ATK_ROLE_LABEL, text="Red",
         ATK_RELATION_LABEL_FOR=grandchild2)
        (grandchild4 AtkAction,
         AtkStateSet, role=ATK_ROLE_CHECK_BOX,
         ATK_RELATION_LABELLED_BY=grandchild5)
        (grandchild5 AtkText,
         role=ATK_ROLE_LABEL, text="Blue",
         ATK_RELATION_LABEL_FOR=grandchild4)
        (grandchild6 AtkAction,
         AtkStateSet, role=ATK_ROLE_CHECK_BOX,
         ATK_RELATION_LABELLED_BY=grandchild7)
        (grandchild7 AtkText,
         role=ATK_ROLE_LABEL, text="Green",
         ATK_RELATION_LABEL_FOR=grandchild6)
    [RFE: add ATK_RELATION_DESCRIBED_BY
    and ATK_RELATION_DESCRIPTION_FOR to match MSAA/DHTML.
    Also, I thought we had ATK_ROLE_FORM, but it seems not to be there.
    Did I miss something?]

Example: form with a selection

HTML source
  • <form>
      <label for="beverage">
        Make a selection:
      </label>
      <select id="beverage">
        <option>Water</option>
        <option>Wine</option>
        <option>Whiskey</option>
      </select>
    </form>

  • (parent role=ATK_ROLE_FORM?)
      (child AtkText,
       role=ATK_ROLE_LABEL,
       ATK_RELATION_LABEL_FOR=child,
       text="Make a selection:")
      (child AtkAction,
       AtkStateSet, AtkSelection,
       attr="html:role=select",
       role=ATK_ROLE_COMBO_BOX,
       ATK_RELATION_LABELLED_BY)
           {grandchild,
            AtkText,
            AtkStateSet=...SELECTABLE, SELECTED...,
            attr="html:role=option",
            role=ATK_ROLE_LIST_ITEM, text="Water")
           (grandchild,
            AtkText,
            AtkStateSet=...SELECTABLE...,
            attr="html:role=option",
            role=ATK_ROLE_LIST_ITEM, text="Wine")
           (grandchild AtkText,
            AtkStateSet=...SELECTABLE...,
            role=ATK_ROLE_LIST_ITEM,
            attr="html:role=option",
            text="Whiskey")
    [note that because the entry field is not editable, but just displays the current
    selection, I think it should not be exposed (especially since it represents a node
     which is not present in the HTML DOM. The list items need not implement AtkAction,
    since the AtkSelection interface is used by the client to select among them.]

Example: form with a multi line selection

HTML source
  • <form>
      <label for="sports">
        Which sports do you like:
        <br>
        <select id="sports"
                multiple="multiple"
                size="3">
          <option>
            <img src="beerglass.gif"
                 alt="Beer"/>
            Baseball
          </option>
          <option>Basketball</option>
          <option>Football</option>
        </select>
      </label>
    </form>

  • (parent role=ATK_ROLE_FORM?)
      (child1 AtkText,
       role=ATK_ROLE_LABEL,
       ATK_RELATION_LABEL_FOR=child2,
       text="Which sports do you like:\n*")
      (child2 AtkObject,
       accessible-name="htmlcat_ibmgapguidecustom.html_sports"
    [not sure exposing the id is a good idea though],
       AtkSelection,
       AtkStateSet=...MULTISELECT...
       attr="html:role=select",
       role=ATK_ROLE_LIST,
       ATK_RELATION_LABELLED_BY=child2)
           (grandchild1,
            AtkHyperText,
            AtkStateSet=...SELECTABLE, SELECTED...,
            attr="html:role=option",
            role=ATK_ROLE_LIST_ITEM, text="*Baseball")
              (great-grandchild AtkImage, AtkHyperlink,
               role=ATK_ROLE_IMAGE,
               attr="html:role=img, link-type=image",
               hyperlink-URI="beerglass.gif",
               hyperlink-indices=[0,0])
           (grandchild2,
            AtkText,
            AtkStateSet=...SELECTABLE...,
            attr="html:role=option",
            role=ATK_ROLE_LIST_ITEM, text="Basketball")
           (grandchild3 AtkText,
            AtkStateSet=...SELECTABLE...,
            role=ATK_ROLE_LIST_ITEM,
            attr="html:role=option",
            text="Football")

Accessibility/Documentation/GNOME2/AtkGuide/Custom (last edited 2011-07-21 17:35:17 by JoanmarieDiggs)