[Gtk-sharp-list] widget destruction

Lluis Sanchez Gual slluis.devel at gmail.com
Wed Mar 9 06:39:41 EST 2011


El dt 08 de 03 de 2011 a les 21:06 -0600, en/na Mike Kestner va
escriure:
> On Tue, Mar 8, 2011 at 1:15 PM, Lluis Sanchez Gual
> <slluis.devel at gmail.com> wrote:
>         GObject doesn't have a Dispose method and doesn't use the
>         IDispose
>         pattern, so we are free to give to Dispose the meaning that
>         better fits
>         our needs.
> 
> 
> Not exactly true.  GObjectClass does have a dispose virtual method.
> It means something similar to the destroy signal on GtkObject/Widget.
> Release references that you hold.  We do not hook into it on
> GLib.Object currently.  Out GLib.Object.Dispose is all managed and
> invokes "unref" stuff.
> 
> 
>         .NET developers expect Dispose to free all memory and
>         resources hold by
>         an object, and the gtk method that better fits this definition
>         is
>         Destroy.
> 
> 
> Whatever we do has to work for non-Widgets too.  There is no concept
> in GObject that says free all memory and resources.  All we can say is
> "we are done with you, go away when you feel like it."  We currently
> map Dispose in GLib.Object to explicitly release our native toggle ref
> and SuppressFinalization.  This is the closest we can get for
> non-widget GObjects.  Therefore, we already have a forced
> "inconsistency" with the way .net users think.

For non-widget GObjects, releasing the reference is probably enough, and
in most cases will have the effect that the user expects. 

> 
> 
>         We can add another method for doing what Dispose currently
>         does (such as
>         Detach or something like that). In any case, I've written
>         thousands of
>         GTK# code in the past years, and I never had the need of such
>         a method,
>         while I've had to write try/finally blocks to destroy dialogs
>         many
>         times.
> 
> 
> You've never disposed a Gdk.Pixbuf, or a Pango.Layout? 

I was talking about calling Dispose on a Widget.

> 
>         There is in fact another source of confusion here. If a widget
>         subclass
>         needs to free its own resources, should it override Dispose or
>         OnDestroyed? It's confusing, because Dispose is not always
>         called when
>         destroying a widget, and OnDestroyed is only called when
>         Destroy is
>         explicitly called (that is, it won't be called if a widget is
>         finalized
>         because all references to it are freed). What we miss here, is
>         a method
>         which is called when an object is finalized (in the gtk+
>         sense), no
>         matter how.
> 
> 
> If Dispose is not called on Destroy, that's a bug.  This may have been
> a bug in the past that got fixed over the course of the ref management
> saga over the last 10 years.  I do recall it being a problem at one
> point.  If it still exists, I'm interested in repro samples if they
> aren't already filed.

I had a lot of problems because of this issue in the past. The issue was
reported here https://bugzilla.novell.com/show_bug.cgi?id=324623, but
the bug was closed as WONTFIX, so I ended replacing all Dispose
overrides by OnDestroyed overrides. It doesn't like this is fixed
nowadays. I just wrote a Gtk.Label subclass with overriden Dispose, and
it is not called if I call Destroy.

> 
> 
>         What I propose is implementing the Dispose pattern in this
>         way:
>         
>              * Add a Dispose method which calls Destroy. That Dispose
>         method
>                must be sealed.
> 
> 
> Dispose must exist for non-Widget GLib.Objects.  For it to exist on
> Widget, that means it has to be virtual on GLib.Object.  I didn't
> think you can "seal" an overridden method, but I'm not certain it
> would be necessary.  Dispose implementors should always chain to base
> anyway, right?  I thought it was fairly standard to post-call
> base.Dispose ().

Yes, you can seal an overriden method to avoid it to be overriden by
subclasses.

>  
>              * Add a new Dispose(bool disposing) method, protected and
>         virtual.
>              * In the OnDestroyed handler, call Dispose(true),
>                GC.SuppressFinalize (this), and free the ref.
>              * In the GLib.Object finalizer, call Dispose(false) and
>         free the
>                ref.
> 
> 
> No ref management can actually happen in the finalizer since it runs
> on another thread.  Calling Dispose(false) then only perpetuates the
> life of the object.  Right now we queue the ToggleRef for disposal in
> an idle handler from the finalizer to get it onto the gui thread.
> Queueing the object just to run Dispose would be a bit of a step
> backwards.  I guess I'd like to understand what the use case is for
> stuff that's happening in those Dispose handlers that would need to be
> invoked from the finalizer thread.

Subclasses may need to free their own unmanaged resources, which may not
be related to gtk at all. For example, I could implement a widget
subclass which pinvokes a C api to get some data, which has to be
explicitly freed. I would free that data in the finalizer, but since the
finalizer will not be called if the object is explicitly disposed, I
also have to free that data in the Dispose method. So, I will end having
a DeleteMyData method which is called from the finalizer and from
Dispose.

The Dispose pattern provides an standard solution to the above scenario.
It states the need for a Dispose(bool disposing) method, to be called
from Dispose and from the finalizer. The 'disposing' parameter is 'true'
when calling from Dispose, meaning that it is safe to access other
reference objects, and it is 'false' when called from the finalizer,
meaning that only unmanaged data should be accessed.

There is some documentation about this pattern here:

http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx

Lluis.





More information about the Gtk-sharp-list mailing list