This section discusses concepts that apply to all widgets,
including memory management and certain special states
widgets can be in. It's a "conceptual" section; however,
the concepts are very important to practical topics covered
later in the book.
Widget resource and memory management is mostly
automatic. However, there are a couple of "gotchas" to
keep in mind if you're doing more complicated things.
A widget can be destroyed at any time by calling gtk_widget_destroy() (shown in Figure 21);
destroying a widget frees any associated memory and other
resources. If the widget is inside a container, it is
automatically removed from the container before it's
destroyed. It's worth noting that
gtk_widget_destroy() is simply another name for gtk_object_destroy(); GtkObjects have "virtual destructors"
so gtk_object_destroy() will
always do the right thing.
Internally, a reference count is maintained for all
widgets (actually, all
GtkObjects). Objects begin their life with a
reference count of 1, even though they have not yet been
referenced. At this stage the object is said to be floating and is flagged as such. It
is possible to remove the object's initial reference;
this is called sinking the
floating object and will destroy the object if the
floating reference was the only one.
Containers first reference and then sink any floating
widgets that are added to them. By sinking a widget, a
container "takes ownership" of it for resource management
purposes. Thus, the reference count of the widget remains
1, but the object is no longer flagged as floating. When
a widget is removed from a container---or the container
is destroyed---the reference count is decremented to 0.
When an object's reference count reaches 0, it is
destroyed.
In practice, this means that you only have to destroy
toplevel widgets; any widgets that are inside a container
will be destroyed along with the container.
There's a danger here, however. Sometimes you want to
remove a widget from a container; perhaps some element of
your interface is optional or only appears under certain
circumstances. When you remove the widget (using gtk_container_remove()), it will be
unreferenced, its reference count will drop to 0, and it
will be destroyed. To avoid this situation, you should
add a reference to the widget before you remove it. Figure 22 lists the
functions to manipulate reference counts.
gtk_object_ref() and gtk_object_unref() have widget-specific
variants (gtk_widget_ref(),
etc.) but the object and widget versions are completely
synonymous. The widget-specific versions are leftovers
from earlier versions of GTK+.
So to safely remove a widget from a container, you might
do this:
gtk_widget_ref(widget);
gtk_container_remove(container, widget);
|
The widget now has one reference, held by your code. At
some point you'll need to release the reference,
destroying the widget. (It would make sense to do so
after re-adding the widget to some other container, for
example.)
It's worth pointing out that removing widgets from
containers is uncommon; in general it's faster to simply
hide the widget with
gtk_widget_hide(), then
gtk_widget_show() it at some later time.
gtk_object_sink() is used
almost exclusively in widget implementations, when you
expect to be the primary "owner" of an object. If an
object is not "floating",
gtk_object_sink() has no effect. To claim ownership
of a widget, do this:
gtk_widget_ref(widget);
gtk_object_sink(GTK_OBJECT(widget));
|
This code adds one reference to the widget; if the widget
was "floating," it also subtracts one reference. If the
widget was not floating,
gtk_widget_sink() has no effect.
It's important to understand the details because in some
cases they can be important. But most of the time, you
can get by with a few simple rules:
-
You must destroy any toplevel widgets when you are
done with them, but child widgets are destroyed
automatically.
-
If you want to remove a widget from a container
without destroying it, you must first add a reference
to the widget.
-
If you add a reference to a widget, you are
responsible for unreferencing the widget again when
you're done with it.