Objects of type
GObject and its subclasses are wrapped using a
gtkobj smob. This smob is called the proxy for the object. It holds
the C pointer and it adds 1 to the reference count of the object. The proxy
is kept alive as long as the object exists. When the proxy is no longer used
from Scheme, and the object is also unused from anywhere in Gtk, then the
proxy and object are destroyed together.
The proxy keeps a list of “protects” which are Scheme procedures installed
as callbacks by
gtk-signal-connect etc. Those protects are kept alive
as long as the object lives but of course they're not themselves a reason to
keep the object alive, an object with callbacks can still be garbage
collected. A similar global list of protects is used for callbacks on global
things like like
Some care must be taken with garbage collection. Objects in use from Scheme
variables etc are marked in the usual way, and then for
widgets marking recurses through the children too (any with proxies). Proxied
objects still in use from Gtk C code are then identified by looking at their
reference counts. A count of more than the 1 which the proxy puts plus
another 1 if it's in a proxied container means that somebody somewhere is
holding a reference to the object in a way that Guile-Gtk's marking has not
traversed. Such a reference is called “external” and objects with external
references are marked (and thus kept alive).
It might be wondered if just waiting for an object to have a reference count of 1 (its proxy) would be enough to know it can be garbage collected (when unreachable from Scheme). In such a system a container with refcount 1 would be collected, and then on the next GC its children would be down to a count of 1 to be collected too. But attached signal handler procedures can stop that from working. Consider container C holding widget W, and a Scheme code signal handler H connected to W and which acts on C. W has a refcount 2 and would be kept alive, so its handler H must be kept, and H refers to C, so C is kept, ie. none of the three is ever collected. The key is that refcount 2 is not in fact an absolute reason to keep W alive, rather it's a reference from C and so ought to depend on whether C is to be kept. Circular references like this occur all the time in Lisp and the way to treat them is to let marking recurse through all genuinely wanted objects, leaving unwanted objects all collected together, no matter what clusters of possibly circular references they might have between themselves.
Strictly speaking to be completely safe against circular references Guile-Gtk
would have to know and follow all references Glib and Gtk establish between
objects. But in practice just
GtkContainer children is enough, because
Gtk's references normally form a tree, it's only Scheme signal handlers
referring up to parent container widgets which create cycles.
Objects which are not sub-classes of
GObject are handled by a simpler
“boxing” system. This includes resources like
GdkCursor, and types
that are more or less user-level structures like
gtkboxed smob holds the C pointer to the object plus its type in the
form of an index into the Guile-Gtk
type_info_tab table. That table
GType value plus certain other information.
Boxed types each have their own specific
declared explicitly in the .defs file, such as
When a smob is created a reference is added, so the object stays alive while
in use from Scheme. When the smob is garbage collected, the unref function is
called. Because there's no signal handlers attached to boxed objects the
circular references problem for
GObject above doesn't occur.
In the current code, whenever a boxed type is returned a new smob is created
for it. No attempt is made to find and re-use an existing smob holding the
same pointer (and type). This is simple, but it's also the reason boxed types
can't be compared with
eq?. A smob “
equalp” function could
compare pointers, but it's not clear if that would be the best thing.
equal? normally looks into the contents of objects, so one might want
it for instance to test whether two
GdkRegions are the same area, or
something like that, instead of only the same object.
GTypes are represented by a smob holding the
GType value (an
integer, though actually it's a pointer Glib has converted to an integer).
GType values are never destroyed, so there's no ref/unref to apply. A
new smob is created whenever a
GType is returned, no attempt is made to
find and re-use an existing smob for it. A smob equality function allows
types to be compared with
Guile-Gtk functions taking a
GType also accept a Scheme symbol, with
the name looked up to get the actual
GType value to pass down to C.
g_type_from_name gives types which have been initialized (or are
builtin), and in addition Guile-Gtk has a table of
to call, such as
GtkVBox. But that table
is limited to the types appearing in the .defs files, there's nowhere
in Glib or Gtk recording the names of all initializable types and classes.