The add and remove functions do not have
a default implementation (well, technically they do:
the default implementation prints a warning that they
aren't implemented). All containers should override
these functions; their corresponding signals are
emitted when library users call
gtk_container_add() and
gtk_container_remove(). For containers that
normally require parameters when adding children (such
as GtkBox and GtkTable), the add method should simply use
reasonable defaults.
GtkBin implements an add
method as follows:
static void
gtk_bin_add (GtkContainer *container,
GtkWidget *child)
{
GtkBin *bin;
g_return_if_fail (container != NULL);
g_return_if_fail (GTK_IS_BIN (container));
g_return_if_fail (child != NULL);
g_return_if_fail (GTK_IS_WIDGET (child));
bin = GTK_BIN (container);
g_return_if_fail (bin->child == NULL);
gtk_widget_set_parent (child, GTK_WIDGET (bin));
bin->child = child;
if (GTK_WIDGET_VISIBLE (child->parent))
{
if (GTK_WIDGET_REALIZED (child->parent) &&
!GTK_WIDGET_REALIZED (child))
gtk_widget_realize (child);
if (GTK_WIDGET_MAPPED (child->parent) &&
!GTK_WIDGET_MAPPED (child))
gtk_widget_map (child);
}
if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (container))
gtk_widget_queue_resize (child);
}
|
Notice the required parts of the add method:
-
gtk_widget_set_parent()
is called to set the widget's parent; this fills in
widget->parent
and handles reference counting and some other
internal details.
-
The container saves a pointer to the child; this is
easy for GtkBin, since
there is only one child and it goes in bin->child.
-
If the container has been shown (i.e., if its GTK_VISIBLE flag is set),
parent and child's
GTK_REALIZED and
GTK_MAPPED states are synchronized. That is,
the child is realized and mapped if the parent is
realized and mapped.
-
If both parent and child have been shown, a resize
is queued. That is, layout will be recalculated in
light of the new child.
The remove method reverses the process; here is its
implementation:
static void
gtk_bin_remove (GtkContainer *container,
GtkWidget *child)
{
GtkBin *bin;
gboolean widget_was_visible;
g_return_if_fail (container != NULL);
g_return_if_fail (GTK_IS_BIN (container));
g_return_if_fail (child != NULL);
g_return_if_fail (GTK_IS_WIDGET (child));
bin = GTK_BIN (container);
g_return_if_fail (bin->child == child);
widget_was_visible = GTK_WIDGET_VISIBLE (child);
gtk_widget_unparent (child);
bin->child = NULL;
if (widget_was_visible)
gtk_widget_queue_resize (GTK_WIDGET (container));
}
|
A remove method is little more than a wrapper for gtk_widget_unparent that queues a
resize if necessary. Most remove methods would check
the container's
GTK_VISIBLE flag before queueing a resize, just
as gtk_bin_add() does; GtkBin does not because toplevel
widgets like GtkWindow
derive from it, and those widgets always queue a
resize, regardless of visibility.