Next: , Previous: Example Programs, Up: Top

17 Internals

17.1 GObject

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 gtk-timeout-add.

Some care must be taken with garbage collection. Objects in use from Scheme variables etc are marked in the usual way, and then for GtkContainer 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.

17.2 Boxed objects

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 GdkRegion.

A 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 holds the GType value plus certain other information.

Boxed types each have their own specific ref/unref functions, declared explicitly in the .defs file, such as gdk_cursor_ref. 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.

17.3 GType

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 equal?.

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 get_type functions to call, such as gtk_vbox_get_type for 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.