Wrapping ATK

Copyright © 2006-2007 Marcus von Appen marcus@sysfault.org

Free to distribute in any way. Just keep the list of copyright holders intact, please.

Implementing ATK

ATK is implemented using the Glib GType and interface system and thus relies heavily on it. It uses singleton objects to ensure that it will stay within a process space (due to the Glib object system).

The first thing to do is to implement the missing interfaces on two vital class types of ATK, AtkUtilClass and AtkObjectClass.

AtkUtilClass defines several interfaces, which are used to get implementation specific information such as the ATK implementation toolkit name (e.g. “gail”), the root object for the application which uses it and method hooks for events.

At first it is necessary to create a type instance within the Glib system, which is done by simply referencing its type.

AtkUtilClass *uclass;
AtkObjectClass *oclass;

g_type_init (); /* GType system initialization. */

/* Ref' the AtkUtilClass type to get its type class, which
 * we can use to bind our own functions.
 */
uclass = g_type_class_ref (ATK_TYPE_UTIL);

/* Bind our functions to the function slots:
 * atk_get_toolkit_name()
 * atk_get_toolkit_version()
 * atk_get_root()
 * atk_add_global_event_listener()
 * atk_remove_global_event_listener()
 */
uclass->get_toolkit_name = _own_get_toolkit_name;
uclass->get_toolkit_version = _own_get_toolkit_version;
uclass->get_root = _own_get_root;
uclass->add_global_event_listener = _own_add_global_event_listener;
uclass->remove_global_event_listener = _own_remove_global_event_listener;

/* Release our received reference. */
g_type_class_unref (uclass);

/* Ref' the AtkObjectClass type to bind our functions. */
oclass = g_type_class_ref (ATK_TYPE_OBJECT);

/* Bind the functions:
 * atk_object_get_n_accessible_children()
 * atk_object_ref_accessible_child()
 * atk_object_get_index_in_parent()
 */
oclass->get_n_children = _own_get_n_children;
oclass->ref_child = _own_ref_child;
oclass->get_index_in_parent = _own_get_index_in_parent;

/* Release our received reference. */
g_type_class_unref (oclass);
  

Note: atk_add_global_event_listener() will be called by the AT-SPI bridge with event_type parameters, which are possibly prefixed with Gtk:. You might want to cut that to match an own scheme.

Now that we bound the most necessary functions, let's look at the bridging module, atk-bridge, shipped with the AT-SPI package.

The atk-bridge shared object module uses the Glib module mechanisms to be loaded and unloaded and contains two functions, which have to be invoked for starting and stopping the bridge. Starting the bridge is done via gnome_accessibility_module_init(), stopping it via gnome_accessibility_module_shutdown(). As we have set up all functions of our most basic types, we will go straightforward to load the bridge.

static void (*_init) (void); static void (*_stop) (void);
...
GModule *module;

module = g_module_open ("path/to/atk-bridge.so", G_MODULE_BIND_LAZY);
if (module)
{
    if (!g_module_symbol (module, "gnome_accessibility_module_init", (gpointer *) &_init) ||
        !g_module_symbol (module, "gnome_accessibility_module_shutdown", (gpointer *) &_stop))
    {
        /* Symbols could not be resolved, do some error handling. */
    }
}

Calling _init() now will invoke the bridge, which in turn will make calls to the different AtkUtil interfaces to receive information about the application and to set up its hooks.

The bonobo backend relies upon the glib context system for polling sockets and descriptors and sending events around. Thus the glib context used by the ATK wrapper has to be iterated periodically in order to let it interact with its environment through the bonobo system.

g_main_context_iteration (g_main_context_default (), FALSE);

This line of code should be placed somewhere in the main loop of the application or toolkit, so that it will be executed periodically to ensure that the interaction between the ATK implementation and the underlying AT-SPI system will work.

docs/atk.txt · Last modified: 2010/03/22 08:00 by marcusva
Driven by DokuWiki Blog RSS feed