2008년 1월 11일 금요일

Using AT-SPI from IronPython (2)

Before continuing, let me mention that all the relevant code is in the FePy repository:
https://fepy.svn.sourceforge.net/svnroot/fepy/trunk/atspi/

Now IIOP.NET is built, it's time to compile IDL. IDL stands for "Interface Description Language", and it is used to (surprise) describe the interface. AT-SPI's CORBA interface is described in /usr/share/idl/at-spi-1.0/Accessibility.idl, and it includes a bunch of other files. Some of these files are in different directories, so one needs to specify them.

The compiler built is under IDLToCLSCompiler/IDLCompiler/bin. Copy these files (IIOPChannel.dll, IDLPreprocessor.dll, IDLToCLSCompiler.exe) to the current directory, and run:

$ mono IDLToClsCompiler.exe \
-idir /usr/share/idl/bonobo-2.0 \
-idir /usr/share/idl/bonobo-activation-2.0 \
Accessibility /usr/share/idl/at-spi-1.0/Accessibility.idl


This should produce Accessibility.dll in the same directory. build.sh in the repository automates the process up to this point (download, build, and IDL compilation).

So how does one connect to the server? This is "a well known problem" that has its own FAQ entry. Basically, one obtains IOR, "Interoperable Object Reference", by out-of-band mean, as one gets URL from the bookmark. After one got the first object reference, one can follow links to other objects.

It turns out that AT-SPI publishes IOR as a property of X root window under the name "AT_SPI_IOR". Now one could go read X protocol specification and manually construct GetProperty request (opcode 20), etc., but there is an easier way. xprop utility can display X properties, so one runs "xprop -root AT_SPI_IOR" and parses the output. xprop.py in the repository implements this.

Now IOR is a long sequence of hexademical digits, and one needs a tool to decode it. ior-decode-2 in orbit2 package can do so. If you decode IOR from xprop, you can notice a problem. AT-SPI (actually CORBA implementation it is using, namely ORBit2) uses Unix domain socket by default, but IIOP.NET can't use it. One solution is in the ORBit2 FAQ I linked above. Create .orbitrc with this line.

ORBIIOPIPv4=1


This post is already quite long, so let's quickly skim the rest. corba.py implements the necessary initializations from IIOP.NET documentation. typed.py is a workaround for IronPython's limitation (namely the lack of cast operator), first suggested by Dino Viehland. And this is the meat of cliatspi.py.

orb = corba.init()
ior = xprop.get('AT_SPI_IOR')
obj = orb.string_to_object(ior)
registry = typed.typedproxy(obj, Accessibility.Registry)


tree.py is an example AT-SPI client I wrote, printing a tree of accessible objects in the current desktop. It imports cliatspi on IronPython, but imports an existing AT-SPI binding on CPython. (I used one in Debian python-at-spi package.) As IDL is language-neutral, this script actually runs identically on both CPython and IronPython. Extending tree.py to be a useful tool like UISpy on Windows is left as an exercise to the readers.