Switch GLib.Object to Dispose(bool) pattern.

* glib/Object.cs: move finalization queue to ToggleRef and make
    Dispose() non-virtual with a protected virtual Dispose(bool).
    Also added a WarnOnFinalize static property to produce nags for
    undisposed objects.
* glib/ToggleRef.cs: add finalization queue and QueueUnref method.
* gtk/NodeStore.cs: override Dispose(bool)
* gtk/Widget.custom: override Dispose(bool)
This commit is contained in:
Mike Kestner 2011-03-25 12:22:04 -05:00
parent 6be0718ff2
commit 1c980d6e71
4 changed files with 66 additions and 49 deletions

View file

@ -35,67 +35,53 @@ namespace GLib {
ToggleRef tref;
bool disposed = false;
static Dictionary<IntPtr, ToggleRef> Objects = new Dictionary<IntPtr, ToggleRef>();
static List<ToggleRef> PendingDestroys = new List<ToggleRef> ();
static bool idle_queued;
~Object ()
{
lock (PendingDestroys) {
lock (Objects) {
if (Objects[Handle] is ToggleRef)
PendingDestroys.Add (Objects [Handle]);
Objects.Remove (Handle);
}
if (!idle_queued){
Timeout.Add (50, new TimeoutHandler (PerformQueuedUnrefs));
idle_queued = true;
}
}
if (WarnOnFinalize)
Console.Error.WriteLine ("Unexpected finalization of " + GetType() + " instance. Consider calling Dispose.");
Dispose (false);
}
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void g_object_unref (IntPtr raw);
static bool PerformQueuedUnrefs ()
{
ToggleRef[] references;
lock (PendingDestroys){
references = new ToggleRef [PendingDestroys.Count];
PendingDestroys.CopyTo (references, 0);
PendingDestroys.Clear ();
idle_queued = false;
}
foreach (ToggleRef r in references)
r.Free ();
return false;
}
public virtual void Dispose ()
public void Dispose ()
{
if (disposed)
return;
Dispose (true);
disposed = true;
ToggleRef toggle_ref;
if (Objects.TryGetValue (Handle, out toggle_ref))
Objects.Remove (Handle);
try {
if (toggle_ref != null)
toggle_ref.Free ();
} catch (Exception e) {
Console.WriteLine ("Exception while disposing a " + this + " in Gtk#");
throw e;
}
handle = IntPtr.Zero;
GC.SuppressFinalize (this);
}
protected virtual void Dispose (bool disposing)
{
ToggleRef tref;
lock (Objects) {
if (Objects.TryGetValue (Handle, out tref)) {
tref.QueueUnref ();
Objects.Remove (Handle);
}
}
handle = IntPtr.Zero;
if (tref == null)
return;
if (disposing)
tref.Free ();
else
tref.QueueUnref ();
}
public static bool WarnOnFinalize { get; set; }
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr g_object_ref (IntPtr raw);
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void g_object_unref (IntPtr raw);
public static Object GetObject(IntPtr o, bool owned_ref)
{
if (o == IntPtr.Zero)

View file

@ -116,6 +116,37 @@ namespace GLib {
}
}
static List<ToggleRef> PendingDestroys = new List<ToggleRef> ();
static bool idle_queued;
public void QueueUnref ()
{
lock (PendingDestroys) {
PendingDestroys.Add (this);
if (!idle_queued){
Timeout.Add (50, new TimeoutHandler (PerformQueuedUnrefs));
idle_queued = true;
}
}
}
static bool PerformQueuedUnrefs ()
{
ToggleRef[] references;
lock (PendingDestroys){
references = new ToggleRef [PendingDestroys.Count];
PendingDestroys.CopyTo (references, 0);
PendingDestroys.Clear ();
idle_queued = false;
}
foreach (ToggleRef r in references)
r.Free ();
return false;
}
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void g_object_add_toggle_ref (IntPtr raw, ToggleNotifyHandler notify_cb, IntPtr data);

View file

@ -202,13 +202,13 @@ namespace Gtk {
#region Gtk.TreeIter handling
ArrayList gc_handles = new ArrayList ();
public override void Dispose ()
protected override void Dispose (bool disposing)
{
// Free all the GCHandles pointing to the iters since they won't be garbage collected
foreach (System.Runtime.InteropServices.GCHandle handle in gc_handles)
handle.Free ();
base.Dispose ();
base.Dispose (disposing);
}
internal void GetIter (ITreeNode node, ref TreeIter iter)

View file

@ -376,12 +376,12 @@ public void Path (out string path, out string path_reversed)
base.CreateNativeObject (names, vals);
}
public override void Dispose ()
protected override void Dispose (bool disposing)
{
if (Handle == IntPtr.Zero)
return;
InternalDestroyed -= NativeDestroyHandler;
base.Dispose ();
base.Dispose (disposing);
}
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]