[Gtk-sharp-list] widget destruction

Mike Kestner mkestner at gmail.com
Tue Mar 8 22:06:46 EST 2011


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.

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?

> It makes more sense to me that Destroy call Dispose, not vice-versa,
> > and the using (FooDialog) pattern isn't all that compelling to me.
>
> Well, it doesn't matter which method calls which, since calling any of
> them should have the same result.
>

It matters to the extent that we have to avoid cycles, which I believe your
solution addresses.

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.

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 ().


>      * 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.

Implementing the pattern in this way, both Dispose and Destroy have the
> same effect, and the Dispose(disposing) virtual method is always called
> (either as a result of all references being freed or by an explicit
> dispose).
>

I like the idea of Dispose invoking Destroy and doing the real dispose work
in an internal Destroyed handler.  We could make the current Dispose
override in Gtk.Widget do that without chaining to base.Dispose, and have
the Destroyed handler invoke base.Dispose, at least conceptually.

About whether making Dispose/Destroy public or private, the framework
> guidelines recommend using the framework terminology for 'dispose'
> methods, and implement IDisposable explicitly. However, IDisposable is
> implemented by GLib.Object, which doesn't have a Destroy method (Destroy
> is defined by Gtk.Object/Widget), so making Dispose public may be a
> better option in this case. In any case, I think it is ok having both
> public. As Nicholas said, several .NET classes have Dispose/Close
> methods, and it doesn't seem to cause confusion.


Yeah, maybe we can make them coexist without confusing the heck out of
everyone.

Mike
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.ximian.com/pipermail/gtk-sharp-list/attachments/20110308/1b682004/attachment-0001.html 


More information about the Gtk-sharp-list mailing list