This is the Guile wrapper of libgobject
, an implementation of a runtime,
dynamic type system for C. Besides providing an object system to C,
libgobject
's main design goal was to increase the ease with which C code
can be wrapped by interpreted languages, such as Guile or Perl.
This module, (gnome gobject)
, just re-exports procedures from other
modules, so its documentation seems an opportune spot for a more tutorial-like
introduction. So open up a Guile session and let's begin.
First, if you haven't done it, load the appropriate version of Guile-GNOME:
guile> (use-modules (gnome-2))
(gnome gobject)
is based heavily on GOOPS, Guile's object system, so go
ahead and load up that too:
guile> (use-modules (oop goops))
We will leave off the guile>
prompt in the rest of this tutorial. When we
want to show the value of an expression, we use ⇒:
(+ 3 5) ⇒ 8
When communicating with libgobject
, most values need to be
strictly-typed. There is a type class corresponding to each basic type in C:
<gchar>
, <guchar>
, <gboolean>
, <gint>
,
<guint>
, <glong>
, <gulong>
, <gint64>
,
<guint64>
, <gfloat>
, <gdouble>
, and <gchararray>
.
You can make instances of these class with make
:
(make <gboolean> #:value #f) ⇒ #<gvalue <gboolean> 40529040 #f> (make <guint> #:value 85) ⇒ #<gvalue <guint> 4054f040 85> (make <gfloat> #:value 3.1415) ⇒ #<gvalue <gfloat> 40556af0 3.1414999961853> (make <gchararray> #:value "Hello World!") ⇒ #<gvalue <gchararray> 4055af90 Hello World!>
You can get the normal Scheme values back with gvalue->scm
:
(gvalue->scm (make <gchararray> #:value "Hello World!")) ⇒ "Hello World!"
Enumerated values and bitflags are an essential part of many C APIs, and so they
are specially wrapped in the GLib type system. You can create new enumerated
types in Scheme by subclassing <genum>
:
(define-class <foo> (<genum>) #:vtable '#((hello "Hello World" 1) (test "Test" 2)))
Instances are created with make
, just like with the other types:
(make <foo> #:value 'hello) (make <foo> #:value "Hello World") (make <foo> #:value 1) ;; These three all do the same thing ⇒ #<gvalue <foo> 406275f8 (hello Hello World 1)>
If there is an already existing enum or flags class, you can get information about it:
(genum-class->value-table <foo>) ⇒ #((hello "Hello World" 1) (test "Test" 2))
Enums and flags have a special representation on the Scheme side. You can convert them to Scheme values as symbols, names, or as a numeric value.
(define foo (make <foo> #:value 'hello)) (genum->symbol foo) ⇒ hello (genum->name foo) ⇒ "Hello World" (genum->value foo) ⇒ 1
All of the types that GLib knows about are available to Guile, regardless of
which language defined them. GLib implements this via a type system, where every
type has a name. So if you make a type called “Foo” in C, you can get to it in
Scheme via gtype-name->class
:
;; Retrieve the type for the foo enum we made earlier in the tutorial (define copy-of-<foo> (gtype-name->class "Foo")) (eq? <foo> copy-of-<foo>) ⇒ #t (make copy-of-<foo> #:value 2) ⇒ #<gvalue <foo> 40535e50 (test Test 2)>
<gobject>
(GObject
in C) is the basic object type in
libgobject
. (gnome gobject)
allows you to access existing GObject
types, as well as to create new GObject types in Scheme.
Before we start, let's pull in some generic functions that reduce the amount of typing we have to do:
(use-modules (gnome gobject generics))
Let's assume we start with <gtk-window>
from (gnome gtk)
. The
keyword arguments to make
are interpreted as GObject properties to set:
(define window (make <gtk-window> #:type 'toplevel #:title "Hello, World!"))
You can connect to signals on the new instance:
(connect window 'delete-event (lambda (window event) ;; Returns #t to ignore this event #t)) ;; connect is a generic function implemented by ;; gtype-instance-signal-connect
And get and set properties...
(get window 'title) ⇒ "Hello, World!" (set window 'resizable #f) ;; get and set are also generics, implemented by gobject-get-property ;; and gobject-set-property
You can create new GObject types directly from Scheme, deriving either from a C object type or one you made in Scheme.
;; deriving from <gobject> (define-class <test> (<gobject>) ;; a normal object slot my-data ;; an object slot exported as a gobject property (pub-data #:gparam (list <gparam-long> #:name 'test)) ;; a signal with no arguments and no return value #:gsignal '(frobate #f)) ;; deriving from <test> -- also inherits properties and signals (define-class <hungry> (<test>))
Adding a signal automatically defines the default method:
;; This is the default handler for this signal. (define-method (test:frobate (object <test>)) (format #t "Frobating ~A\n" object)) ;; We can override it for subclasses (define-method (test:frobate (object <hungry>)) (next-method) ;; chain up (format #t "I'm hungry\n")) (emit (make <hungry>) 'frobate) ;; Try it!
You can override the initialize
, gobject:get-property
, and
gobject:set-property
methods. For an extended example, see
tic-tac-toe.scm
in the gtk/examples/gtk
directory of the
distribution.