This library converts the elements from GObject Introspection into Lisp-style definitions, based on cl-gobject-introspection.
It’s very easy to create a binding to a new GObject-based library via cl-gobject-introspection-wrapper
:
- Clone this repository into the folder
local-projects
under your Quicklisp installation root, then load the library with(ql:quickload :cl-gobject-introspection-wrapper)
. - Create a package to store the auto-generated symbols from GIR. To avoid potential symbol conflicts,
we write the
defpackage
with an empty:use
clause:(cl:defpackage gtk (:use))
- Use
gir-wrapper:define-gir-namespace
to generate all definitions from the GIR namespace:(gir-wrapper:define-gir-namespace "Gtk")
Note that all the definition symbols are exported automatically.
- If there exist some definitions whose name is not converted correctly or cause symbol conflicts according to Conversion Rules,
you can set up the special variable
gir-wrapper:*quoted-name-alist*
to specify the corresponding symbol for a definition. This could also exclude some definitions by specifying the symbols tocl:nil
so that you can define them by hand later:(cltl2:compiler-let (gir-wrapper:*quoted-name-alist* '((("TextBuffer" . "get_insert") . text-buffer-get-insert) ; Specify a symbol for class method ("CSET_a_2_z" . +cset-a-z-lower-case+) ; Specify a symbol for function, constant, enumeration, class, interface, struct, or function argument. (("Widget" . "is_sensitive") . cl:nil) ; Exclude a class method. ("String" . cl:nil))) ; Exclude a function, constant, enumeration, class, struct, or interface. (gir-wrapper:define-gir-namespace "Gtk" "4.0"))
For portability consideration, we set the variable before
gir-wrapper:define-gir-namespace
, then reset it after that, to avoid using thecompiler-let
in CLTL2:(cl:eval-when (:execute :compile-toplevel :load-toplevel) (cl:setf gir-wrapper:*quoted-name-alist* '((("TextBuffer" . "get_insert") . text-buffer-get-insert) ("CSET_a_2_z" . +cset-a-z-lower-case+) (("Widget" . "is_sensitive") . cl:nil) ("Widget")))) (gir-wrapper:define-gir-namespace "Gtk" "4.0") (cl:eval-when (:execute :compile-toplevel :load-toplevel) (cl:setf gir-wrapper:*quoted-name-alist* '()))
In our rule definitions:
*
is a placeholder that stands for any type.[]
denote an optional part of the name./
splits multiple optional words.
GIR definition | Lisp definition |
---|---|
Foo | (progn (defun foop (instance)) (deftype foo ())) |
FOOBar | (progn (defun foo-bar-p (instance)) (deftype foo-bar ())) |
GIR definition | Lisp definition |
---|---|
Foo new/create[_from/for/with_bar](* arg1, * arg2, ...) | (defun make-foo (&key arg1 arg2 ...)) |
Foo new/create_from/for/with_bar(* arg) if arg is used by another constructor | (defun make-foo (&key bar)) |
Note that the constructors with identical name after conversion will be merged into a single Lisp function, and which constructor to be called is determined by the arguments provided for this function.
In class/interface/struct Foo
:
GIR definition | Lisp definition |
---|---|
void set_bar(*) | (defun (setf foo-bar) (value instance)) |
* get_bar() | (defun foo-bar (instance))) |
* set_bar[_is_baz](boolean) | (defun (setf foo-bar[-baz]-p) (value instance)) |
boolean [bar_]is_baz() | (defun foo[-bar]-baz-p (instance)) |
boolean get[_bar_is]_baz() | (defun foo[-bar]-baz-p (instance)) |
boolean [bar_]has/should/can_baz() | (defun foo-[bar-]has/should/can-baz-p (instance)) |
* bar(* arg1, * arg2, ...) | (defun foo-bar (instance arg1 arg2 ...)) |
GIR definition | Lisp definition |
---|---|
FOO_BAR = 123 | (alexandria:define-constant +foo-bar+ 123 :test #'equal) |
GIR definition | Lisp definition |
---|---|
Foo { Bar, Baz, ... } | (progn (defconstant +foo-bar+ 0) (defconstant +foo-baz+ 1) ...) |