#use wml::tmpl::main title="gspi -- Guile based interactive binding the GNOME Assistive Technology Service Provider Interface" PAGE=programming SUBPAGE=gspi

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

<P>
The <A href="http://developer.gnome.org/projects/gap/tech-docs/at-spi-docs/book1.html">Assistive Technology Service Provider Interface (AT-SPI)</A>
is a very nice infrastructure for querying information from 
a GNOME desktop.  There are <A href="http://cvs.gnome.org/bonsai/rview.cgi?cvsroot=/cvs/gnome&dir=at-spi/idl">IDL bindings</A> for it, but
the most commonly used binding is cspi, a C library for accessing
the AT-SPI.
<P>
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 
<A href="$(ROOT)/scheme.html#guile">Guile</A>.
<P>
<H2><A name="example">Example</A> usage</H2>
<P>
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.
<P>
<pre>
Guile AT-SPI Version 0.0.2
gspi&gt; (spi-init)
0
gspi&gt; (define apps (applications))
gspi&gt; apps
(#&lt;Accessible 0x80e62a8, name="gnome-session", role=application&gt; #&lt;Accessible 0x80e6130, name="nautilus", role=application&gt; #&lt;Accessible 0x80e54b0, name="gnome-panel", role=application&gt; #&lt;Accessible 0x80e5eb8, name="mixer_applet2", role=application&gt;)
gspi&gt; (define nautilus (cadr apps))
gspi&gt; (children nautilus)
(#&lt;Accessible 0x80e6560, name="Desktop", role=frame&gt;)
gspi&gt; (find nautilus focused?)
(#&lt;Accessible 0x80fc9f0, name="Start Here", role=unknown&gt;)
gspi&gt; (find nautilus (lambda (obj) (eq? (get-role obj) 'menu)))
(#&lt;Accessible 0x80e8ad8, name="", role=menu&gt;)
gspi&gt; (define nautilus-menu (car (find nautilus (lambda (obj) (eq? (get-role obj) 'menu)))))
gspi&gt; (children nautilus-menu)
()
gspi&gt; nautilus-menu
\#&lt;Accessible 0x80e8ad8, name="", role=menu&gt;
gspi&gt; (next-child nautilus-menu)
\#&lt;Accessible 0x80e8960, name="", role=menu-item&gt;
gspi&gt; (next-child nautilus-menu 2)
\#&lt;Accessible 0x80e87e8, name="", role=menu&gt;
gspi&gt; (next-child nautilus-menu 3)
\#&lt;Accessible 0x80e8440, name="", role=menu&gt;
gspi&gt; (next-child nautilus-menu 4)
\#f
gspi&gt; (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&gt; (map (lambda (obj) (list (get-layer obj) (get-extents obj)))
           (toplevels))
((window (0 0 1024 768)) (window (0 740 1024 28)) (window (0 0 1024 24)))
gspi&gt;
</pre>
<H2>Emacs support</H2>
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.
<P>
Example:
<pre>
*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=<Alt>f;<Alt>f;)
         | |     +-- menu Edit (click=<Alt>e;<Alt>e;)
         | |     +-- menu View (click=<Alt>v;<Alt>v;)
         | |     +-- menu Search (click=<Alt>s;<Alt>s;)
         | |     +-- menu Tools (click=<Alt>t;<Alt>t;)
         | |     +-- menu Documents (click=<Alt>d;<Alt>d;)
         | |     +-- menu Help (click=<Alt>h;<Alt>h;)
         | |     +-- menu Debug (click=<Alt>d;<Alt>d;)
         | +-- panel
         | +-- split-pane
         +-- filler
</pre>

<H2><A name="download">Download</A></H2>
<A href="$(ROOT)/gspi-0.0.8.tar.gz">Download gspi-0.0.8.tar.gz</A>

<H2>Open questions</H2>
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 <TT>(make-thread spi-event-loop)</TT>
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?
<P>
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 <em>three</em> different worlds,
which does not appear to me as very useful.

