forked from AuroraMiddleware/gtk
4af33fa24d
still some gnits left, but keep working on it ;) -timj
202 lines
7.2 KiB
Plaintext
202 lines
7.2 KiB
Plaintext
How ref counting works within Gdk and Gtk
|
|
=========================================
|
|
|
|
Each data structure that provides ref counting offers a bunch of
|
|
functions that follow these conventions:
|
|
|
|
*_new: Create a new structure with a reference count of 1.
|
|
*_ref: Increase ref count by one.
|
|
*_unref: Decrease ref count by one. If the count drops to zero,
|
|
run aprropriate finalization code and free the memory.
|
|
No user visible actions should take place, like
|
|
destryoing windows, etc.
|
|
|
|
Some structures also provide a *_destroy function, but it is generally
|
|
unrelated to freeing the memory. `Destroying' merely renders an
|
|
object `unusable'. But as long as there are references to it, it will
|
|
stick around.
|
|
|
|
GdkWindow
|
|
---------
|
|
|
|
A GdkWindow has to be explicitely destroyed with gdk_window_destroy.
|
|
This will send out a request to destroy this window and all its
|
|
children, and will decrement the ref_count of the GdkWindow by one.
|
|
Thus, it releases the inital reference created by gdk_window_new.
|
|
|
|
All GdkWindows are kept in a hash table to translate from their XId to
|
|
the actual structure and the pointer in the hash table is reflected in
|
|
the reference count. When a DestroyNotify event is received for a
|
|
particular GdkWindow, it is removed from the hash table and the
|
|
ref_count is updated accordingly.
|
|
|
|
You can call gdk_window_destroy more than once on a particular
|
|
GdkWindow, it will only be destroyed when it hasn't been yet. The
|
|
ref_count is *always* decremented, tho. Be careful.
|
|
|
|
GdkPixmap
|
|
---------
|
|
|
|
There is no gdk_pixmap_destroy function. The Pixmap is destroyed when
|
|
the last reference to it vanishes.
|
|
|
|
GdkPixmaps are kept in the same hash table as GdkWindows but the
|
|
pointer in the hash table is *not* reflected in the ref_count.
|
|
|
|
This works only when Pixmaps never get XEvents. I'm not sure if this
|
|
is the case.
|
|
|
|
GdkBitmap
|
|
---------
|
|
|
|
A GdkBitmap is only another name for a special use of GdkPixmap.
|
|
|
|
GdkVisual
|
|
---------
|
|
|
|
There are no *_new or *_destroy functions and the *_ref and *_unref
|
|
functions are noops. GdkVisuals are static structures and thus do not
|
|
need reference counting. The ref counting functions are only there
|
|
for extra defensive programming.
|
|
|
|
GdkColormap
|
|
-----------
|
|
|
|
Nothing special. There is no gdk_colormap_destroy function.
|
|
|
|
GdkFont / GdkFontSet
|
|
--------------------
|
|
|
|
GdkFont and GdkFontSet are equivalent as far as ref counting is
|
|
concerned. Use gdk_font_ref and gdk_font_unref for both.
|
|
|
|
There is no gdk_font_free or gdk_fontset_free function.
|
|
|
|
GtkAcceleratorTable
|
|
-------------------
|
|
|
|
There is no gtk_accelerator_table_destroy function.
|
|
|
|
GtkTooltips
|
|
-----------
|
|
|
|
There is no gtk_tooltips_destroy function.
|
|
|
|
GtkStyle
|
|
--------
|
|
|
|
There is no gtk_style_destroy function.
|
|
|
|
GtkObject
|
|
---------
|
|
|
|
GtkObjects follow the usual ref_counting strategy, but with a twist.
|
|
|
|
They are created with a ref_count of 1. GtkObjects are able able to
|
|
run finalization code when the ref_count drops to zero but you cannot
|
|
register arbitrary signal handlers to run at finalization time.
|
|
|
|
There is also the old gtk_object_destroy function and the "destroy"
|
|
signal but they are somewhat independent from finalization. Just as
|
|
stated at the top of this text, gtk_object_destroy merely renders an
|
|
object unusable. When the object is a container widget for example,
|
|
it unrealizes that widget, removes all children and disconnects all
|
|
signal handlers. The finalization code is different, it would for
|
|
example free associated memory for text strings and release the
|
|
attached style.
|
|
|
|
[This is the biggest change. Every widget must be revised to have a
|
|
proper "destroy" function, etc. Such a destroy function must be able
|
|
to be called any number of times and generally leave the widget in a
|
|
minimal but consistent state. The "finalization" function is new and
|
|
should perform last-minute cleanup actions. It can assume that the
|
|
"destroy" function has been called as the last function on this
|
|
widget.
|
|
|
|
Essentially, the old "destroy" function has been split into a
|
|
"finalize" plus a "destroy" function.]
|
|
|
|
It is not possible to create GtkObjects with a ref_count of 0 (as it
|
|
is done now) because the first ref/unref pair will destroy it
|
|
unintentionally.
|
|
|
|
To be mostly backward compatible with existing practice, a GtkObject
|
|
leads a more complicated life than the other reference counted structures.
|
|
|
|
When a GtkObject is created, it starts out in a special state called
|
|
"floating" (this is the twist). This means that it is alive and has a
|
|
reference to it, but the `owner' of this reference is not known.
|
|
There are certain `potential owners' that will adopt a floating
|
|
GtkObject. For GtkWidgets the most common adopters are the parent
|
|
widget.
|
|
|
|
When you want to adopt a possibly floating GtkObject, you call
|
|
gtk_object_sink on it. This clears the floating state of the
|
|
GtkObject and decrements the ref_count by one, if it has been floating
|
|
previously. Once the floating state has been cleared, it will never
|
|
be set again.
|
|
|
|
All widgets that are part of the display are linked into a
|
|
parent/child tree. The link from the parent to a child is reflected
|
|
in the ref_count of the child, but the link from the child to the
|
|
parent is not reflected in the ref_count of the parent.
|
|
|
|
Like a GtkObject, a GtkWidget is created with a ref_count of 1 and
|
|
initially flagged as `floating'. As soon as it is added as a child to
|
|
a parent, the `floating' flag is cleared and never will be set again.
|
|
Not even when it is later unparented. The act of clearing the
|
|
`floating' flag also decrements the ref_count of the widget by one.
|
|
|
|
When the widget is unparented, its underlying GdkWindow is destroyed
|
|
(when it has one), it loses its reference from the parent and
|
|
naturally the ref_count is decremented.
|
|
|
|
It is considered a bug if a widget still has a GdkWindow when it is
|
|
being freed.
|
|
|
|
Toplevel widgets, which don't have a `natural' parent, are adopted by
|
|
a special widget, maybe a GtkDisplay or GtkScreen. This special
|
|
parent of all toplevel widgets is never freed. The toplevel widgets
|
|
are added to this parent as soon as they are created. [Maybe this
|
|
special widget will only exist conceptually because toplevel widgets
|
|
are identified by parent == NULL through-out the code.]
|
|
|
|
So, the typical career of a GtkWindow and the GtkButton that sits in
|
|
it looks like this:
|
|
|
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
// window is created with ref_count == 1. It is not flagged as
|
|
// `floating' because it has already been added to the special
|
|
// parent of all toplevel widgets.
|
|
|
|
button = gtk_button_new_with_label ("Yo!");
|
|
|
|
// button->ref_count == 1 and it is flagged as `floating'.
|
|
|
|
gtk_container_add (window, button);
|
|
|
|
// button->ref_count still == 1, but it is no longer `floating'.
|
|
|
|
gtk_widget_show (button);
|
|
gtk_widget_show (window);
|
|
|
|
// The widgets get their GdkWindows, nothing significant happens to
|
|
// the ref_counts.
|
|
|
|
Then, when the user wants to get rid of the window:
|
|
|
|
gtk_widget_destroy (window);
|
|
|
|
// The GdkWindow of `window' and all its child GdkWindows are
|
|
// destroyed.
|
|
|
|
// window is removed from its (conceptual) parent and its ref_count
|
|
// drops to zero. The destroy code of `window' destroyes `button'.
|
|
|
|
// The destriction of the button removes it from its parent, the
|
|
// button->ref_count drops to zero and the button is freed, too.
|
|
|
|
|
|
- Marius Vollmer <mvo@zagadka.ping.de>
|