It's GTK in a Lispy way
λgtk is a cross-platform Lisp interface to the complete GTK+2 family of shared libraries. λgtk currently runs in the following Lisp environments:
and is released under the Lisp Lesser General Public License (LLGPL).
Because GTK is so large and complex λgtk generates its Lisp FFI interfaces from a GTK definition file (gtk.ffi, output by Gary Byers' ffigen program) and an API control file (gtk.api) that you can edit and customize in order to generate more or less inclusive interfaces to GTK. λgtk is organized into two layers: a common file (lambda-gtk-common.lisp) and an implementation file for each target FFI (lambda-gtk-openmcl.lisp, lambda-gtk-cmusbcl.lisp, and so on). With the exception of callbacks (which are required by GTK itself) λgtk uses only a modest set of features from its host environment and is readily portable to other Lisps, including reasonably featured Schemes.
λgtk provides Lisp programmers with the following set of features:
- Portable GUI programming across the supported Lisp environments.
- Automatic conversion between Lisp data (booleans, numbers, strings) and their equivalent GTK types. Function arguments that involve C pointers to ints, floats and doubles are also handled automatically: foreign values are allocated and initialized by the wrappers, the pointers are passed to GTK and then dereferenced and returned to the Lisp caller as multiple values.
- Lisp names for GTK's enums, structs and functions. Lisp names are formed by substituting "-" for "_" and (possibly) converting C library prefixes into exported Lisp package prefixes (see documentation section below).
Lisp accessor functions to read/write slot values in GTK structs.
Accessors are named struct.slot but may include more than one
slot name, e.g.
gtk:Widget.allocation.width. The first argument to all accessors is a pointer to a struct; if the referenced slot is an array then a second required argument provides the index. The last argument to all accessors is an optional value, that, if specified, replaces the current value in the slot. For example:
(gdk:Rectangle.x rect) ; return rect's x value (gdk:Rectangle.x rect 100) ; set rect's x value
- Lisp symbol package(s) that export the GTK API and a read time conditional #+:gtk in *features*.
- A small set of utilities for working with GTK pointers, callbacks and foreign storage in a portable way (see documentation below).
The project provides a complete FFI to GTK in several different Lisps but is missing some obvious functionality. Here is a list of some missing features tagged by implementation difficulty:
- [Easy] Add lisp error handling to gtk:define-signal-handler.
- [Medium] Add support for CLISP and/or UFFI and make sure it works on Windows GTK.
- [Hard] Bitfields and slot accessors to bitfields are not supported in SBCL or CMU. This is actually more of a bug than a missing feature since currently the allocation size and slot offsets of a few structs are incorrect. See next point.
- [Hard?] Generate a gtk-x86.ffi definition file for lambda-gtk, possibly using ffigen. That way lambda-gtk could generate bitfields and bitfield accessors in CMU and SBCL.
- [Medium] Add accessors for "struct array" slots in OpenMCL.
- [Medium?] Port λgtk to Guile. Bill Schottstaedt at CCRMA has a Guile GTK binding already so hopefully his code could be used or adapted.
- [Easy] Define an ASDF installation mechanism for λgtk.
- [Easy] Implement all the examples in the GTK tutorial for testing purposes.
Please contact me if you would like to help out!
Download the λgtk sources and restore it to a directory on your machine.
If you are using OpenMCL, download the OpenMCL GTK Interface and untar it inside OpenMCL's ccl/darwin-headers/ folder:
$ cd /path/to/ccl/darwin-headers $ tar -zxf openmcl-gtk-interface.tar.gz
If you are using SBCL, install Thomas Burdick's Alien Function package and save a new sbcl.core image:
$ tar -zxf sbcl-af-2004-10-22.tgz $ cd sbcl-af $ sbcl --load "system" * (sb-ext:save-lisp-and-die "/tmp/sbcl.core") $ cd /usr/local/lib/sbcl $ mv sbcl.core sbcl.core.orig $ mv /tmp/sbcl.core .
Generate a GTK interface file: cd to the lambda-gtk installation
directory, load the appropriate implementation file and call the
lambda-gtk function. For example, in sbcl it might look like:
$ cd /path/to/lambda-gtk $ sbcl * (load "lambda-gtk-cmusbcl") * (lambda-gtk "gtkffi-cmusbcl.lisp") * (quit)
Compile and load the generated FFI into Lisp. Compiling a full
interface will probably take between two and twelve minutes, depending
on your Lisp implementation and processor speed. Once the interface
is loaded you can start programming in GTK. The examples.lisp file is a fine place to start:
$ sbcl * (load (compile-file "gtkffi-cmusbcl")) * (load "examples") * (hello-world)
Examples range from the canonical "Hello World" to "Scribble Simple", the most complex demo in the GTK tutorial.
Reading the GTK API reference is the best way to learn how to use λgtk: other than the simple symbol translations described in this document and the handful of glue functions shown below λgtk does not add any additional syntax or features of its own to GTK. The generation process is equally simple, there is only one entry point, the lambda-gtk function itself:
(lambda-gtk file . lib-packaging)
Outputs a Lisp/GTK FFI into file. If lib-packaging is true (the default) then GTK symbols are striped of their C library prefixes and placed in Lisp package named after the libraries: GTK, GDK, G, ATK and PANGO. If lib-packaging is false then only the GTK package is created and the Lisp symbols preserve their GTK library prefix. (It is assumed in this case that the user will use the FFI symbols without any package prefixing whatsoever.) Regardless of how lib-packaging is set, Lisp names always substitute the Lisp hyphen "-" in place of the C underbar "_".
The following table shows the effect of lib-packaging on a few representative symbols:
C name lib-packaging true lib-packaging false
gtk:+true+, gtk:+false+, gtk:init-ensure, g:nullptr, g:nullptr?, g:callback,gtk:define-signal-handler, gtk:struct-alloc, gtk:struct-free, gtk:cstring->string, gtk:string->cstring, gtk:cstring-free.
If you use λgtk to develop a GUI interface in Lisp please send a pretty picture!
Here is mine:
[Stable links only, please!]
I would never have attempted this interface without the FFI tools that Gary Byers provides in his OpenMCL distribution. The callback mechanism for SBCL is written Thomas Burdick. Several of the GTK examples are adapted from Mario Mommer's l-gtk distribution.
Associate Professor, Composition/Theory
School of Music, University of Illinois
Urbana, IL 61801 USA
Fax: 1 217 244-4585
Vox: 1 217 244-2684