Re: containers and reference counting



Ron Steinke <rsteinke merilon elfhame net> writes:
> 	I'm counfused about how reference counting works when widgets are
> added to containers. Let's say I have the code
> 
> GtkBin *bin;
> GtkWidget *widget;
> 
> ...  (create the bin, widget)
> 
> gtk_container_add(GTK_CONTAINER(bin), widget);
> 
> Does the add increment the reference count for widget? Do I
> need to gtk_widget_unref(widget) here?
> 
> If I later do
> 
> gtk_container_remove(GTK_CONTAINER(bin), widget);
> 
> does the remove unref the widget? Do I still have a widget, or
> has it been destroyed?
> 

Widgets are created with a so-called floating reference. A floating
reference has no owner, but anyone can remove it. Conventionally, you
remove the floating count if you are keeping a non-transient reference
of your own. gtk_container_add() will a) remove the floating reference
and b) add its own reference. This means that the widget ends up with
1 reference, owned by the container.

The code looks like:
 gtk_object_ref (GTK_OBJECT (child));   /* add reference */
 gtk_object_sink (GTK_OBJECT (child));  /* remove floating, iff it exists */

Once an object is "sunk" (has no floating refence) there is no way to
re-float it. gtk_object_sink() is a no-op if it's called on an
already-sunk object.

When you gtk_container_remove(), the container will unref the widget;
so if you haven't added other references the widget will be finalized.

An example case where you would ref a widget but not sink it is signal
emission. If a widget emits a signal, say an entry emitting "changed",
the widget is referenced during the signal emission and unreferenced
afterward. This makes things much easier for users, since you can go
ahead and for example destroy a window from a callback without
worrying about whether signal emissions on the window are
outstanding. 

However if signal emission sank the widget, a call such as:
 gtk_entry_set_text (entry, "foo");
would add a reference to emit the "changed" signal, strip the floating
reference, then unref the widget, and so gtk_entry_set_text() might
end up finalizing the entry, which would be kind of bad to say the
least.

As long as you always put your widgets in a container, all you have to
remember as an application programmer is that you don't need to
unref() unless you explicitly ref().

Toplevel windows are never floating, they are "born" owned by the GTK+
runtime, and the GTK+ runtime will unref() them when you call
gtk_object_destroy(). So again no need to call unref() unless you
called ref() explicitly.

The "destroy" signal is a way to break reference cycles; it basically
means "detach yourself from all other objects that you reference or
that reference you." So for toplevel windows, it will remove the
toplevel from the list of toplevels owned by GTK+, and thus cause an
unref(); for other widgets, it will do an implicit
gtk_container_remove(), among other things. Also if you destroy a
toplevel all children of the toplevel will be recursively destroyed,
so destroying a toplevel generally drops the refcount to 0 on all
contained widgets.

One case where you commonly need to worry about refcounting is when
moving a widget between containers, where you want to hold a temporary
reference:

 ref (child);
 container_remove (container, child);
 container_add (new_container, child);
 unref (child);

So, more than you ever wanted to know. ;-)

Havoc







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