From 1c980d6e715d111187906eb2745c1c451572e78c Mon Sep 17 00:00:00 2001 From: Mike Kestner Date: Fri, 25 Mar 2011 12:22:04 -0500 Subject: [PATCH] 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) --- glib/Object.cs | 76 +++++++++++++++++++---------------------------- glib/ToggleRef.cs | 31 +++++++++++++++++++ gtk/NodeStore.cs | 4 +-- gtk/Widget.custom | 4 +-- 4 files changed, 66 insertions(+), 49 deletions(-) diff --git a/glib/Object.cs b/glib/Object.cs index d3ee589b4..a5488c98b 100644 --- a/glib/Object.cs +++ b/glib/Object.cs @@ -35,67 +35,53 @@ namespace GLib { ToggleRef tref; bool disposed = false; static Dictionary Objects = new Dictionary(); - static List PendingDestroys = new List (); - 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) diff --git a/glib/ToggleRef.cs b/glib/ToggleRef.cs index 512d14ae4..9823038b4 100644 --- a/glib/ToggleRef.cs +++ b/glib/ToggleRef.cs @@ -116,6 +116,37 @@ namespace GLib { } } + static List PendingDestroys = new List (); + 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); diff --git a/gtk/NodeStore.cs b/gtk/NodeStore.cs index 7e71abbf4..e11780a62 100644 --- a/gtk/NodeStore.cs +++ b/gtk/NodeStore.cs @@ -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) diff --git a/gtk/Widget.custom b/gtk/Widget.custom index dbfd0e207..17fbd48c5 100644 --- a/gtk/Widget.custom +++ b/gtk/Widget.custom @@ -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)]