guile-gtk internals doc
Kevin Ryde <[email protected]>
| Newsgroups | gmane.lisp.guile.gtk |
|---|---|
| Message-ID | <[email protected]> |
I had a nose around the way the gobject reference counting gets done and found it a little tricky to understand. So having nutted it out, or I think I nutted it out, I wrote a few words for the manual. I think refcount vs marking came up on this list a while ago (ages ago), maybe concerning guile-gnome instead of guile-gtk. But in any case the idea of these words is to be a medium-technical overview. 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 in use from Gtk C code are then found 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 pass 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 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 obvious 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 `GdkRegion's are the same area, or something like that, instead of only the same object. 17.3 `GType' ============ `GType's are represented by a smob holding the type 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.