gspi -- Guile based interactive binding the GNOME Assistive Technology Service Provider Interface

Guile based interactive binding the GNOME Assistive Technology Service Provider Interface (At-SPI)

The Assistive Technology Service Provider Interface (AT-SPI) is a very nice infrastructure for querying information from a GNOME desktop. There are IDL bindings for it, but the most commonly used binding is cspi, a C library for accessing the AT-SPI.

Since I come from a Emacs-Lisp background, I really like the dynamic evaluation concept of Lisp and Scheme. Edit-Compile-Run is not what I particularily enjoy. So I decided to write a Scheme binding for AT-SPI, using Guile.

Example usage

Here is a somewhat contrived example of a typical gspi usage session. It should help to get you started despite the lack of Scheme at-spi function documentation, and should also give you an idea what you can use gspi for.

Guile AT-SPI Version 0.0.2
gspi> (spi-init)
gspi> (define apps (applications))
gspi> apps
(#<Accessible 0x80e62a8, name="gnome-session", role=application> #<Accessible 0x80e6130, name="nautilus", role=application> #<Accessible 0x80e54b0, name="gnome-panel", role=application> #<Accessible 0x80e5eb8, name="mixer_applet2", role=application>)
gspi> (define nautilus (cadr apps))
gspi> (children nautilus)
(#<Accessible 0x80e6560, name="Desktop", role=frame>)
gspi> (find nautilus focused?)
(#<Accessible 0x80fc9f0, name="Start Here", role=unknown>)
gspi> (find nautilus (lambda (obj) (eq? (get-role obj) 'menu)))
(#<Accessible 0x80e8ad8, name="", role=menu>)
gspi> (define nautilus-menu (car (find nautilus (lambda (obj) (eq? (get-role obj) 'menu)))))
gspi> (children nautilus-menu)
gspi> nautilus-menu
#<Accessible 0x80e8ad8, name="", role=menu>
gspi> (next-child nautilus-menu)
#<Accessible 0x80e8960, name="", role=menu-item>
gspi> (next-child nautilus-menu 2)
#<Accessible 0x80e87e8, name="", role=menu>
gspi> (next-child nautilus-menu 3)
#<Accessible 0x80e8440, name="", role=menu>
gspi> (next-child nautilus-menu 4)
gspi> (map get-name (find (desktop 0) (lambda (obj) (and (focusable? obj) (visible? obj)))))
("Start Here" "root's Home" "Trash" "Start Here" "" "Error" "Home Folder
View your home folder in the Nautilus file manager" "Terminal
Command line")
gspi> (map (lambda (obj) (list (get-layer obj) (get-extents obj)))
((window (0 0 1024 768)) (window (0 740 1024 28)) (window (0 0 1024 24)))

Emacs support

Since version 0.0.5, gspi also includes Emacs support files. The probably most important and user visible function is gspi-explorer, a tree view of the at-spi information.


*GNOME desktop 0*.

Scheme filter: nil
 --, Redraw
   |-- gnome-session (GAIL V1.2.2 id=1)
   +-- gnome-panel (GAIL V1.2.2 id=2)
   +-- nautilus (GAIL V1.2.2 id=3)
   --, gedit (GAIL V1.2.2 id=9)
     --, frame Untitled 1 - gedit
       --, filler
         --, panel
         | --, panel
         | | --, panel
         | |   |-- unknown grip ()
         | |   --, menu-bar
         | |     +-- menu File (click=f;f;)
         | |     +-- menu Edit (click=e;e;)
         | |     +-- menu View (click=v;v;)
         | |     +-- menu Search (click=s;s;)
         | |     +-- menu Tools (click=t;t;)
         | |     +-- menu Documents (click=d;d;)
         | |     +-- menu Help (click=h;h;)
         | |     +-- menu Debug (click=d;d;)
         | +-- panel
         | +-- split-pane
         +-- filler


Download gspi-0.0.8.tar.gz

Open questions

I did not find a way yet to run the main spi-event-loop without blocking the main Guile evaluation interface. Using Guile threads does not seem to help, since when doing something like (make-thread spi-event-loop) heavy blocking of the main Guile process does still occur. I suspect this might be related to conflicting behaviour between the Guile threading implementation and some pthreads which might get run additionally in spi-event-loop. But to be honest, I do not have a clue here. Some more experienced Guile hackers might perhaps know why this happens?

This also creates the problem that the Emacs support library can not implement event handling currently, because it would need to launch a separate, second gspi process, which would leave me with the situation of having to deal with data in three different worlds, which does not appear to me as very useful.

Last Modified: 2004-03-14 00:22:08
You can view the Source Code of this page