guile-gtk-general
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

guile-gtk internals doc


From: Kevin Ryde
Subject: guile-gtk internals doc
Date: Mon, 17 Sep 2007 11:15:19 +1000
User-agent: Gnus/5.110007 (No Gnus v0.7) Emacs/22.1 (gnu/linux)

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.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]