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:
parent
6be0718ff2
commit
1c980d6e71
4 changed files with 66 additions and 49 deletions
|
@ -35,67 +35,53 @@ namespace GLib {
|
||||||
ToggleRef tref;
|
ToggleRef tref;
|
||||||
bool disposed = false;
|
bool disposed = false;
|
||||||
static Dictionary<IntPtr, ToggleRef> Objects = new Dictionary<IntPtr, ToggleRef>();
|
static Dictionary<IntPtr, ToggleRef> Objects = new Dictionary<IntPtr, ToggleRef>();
|
||||||
static List<ToggleRef> PendingDestroys = new List<ToggleRef> ();
|
|
||||||
static bool idle_queued;
|
|
||||||
|
|
||||||
~Object ()
|
~Object ()
|
||||||
{
|
{
|
||||||
lock (PendingDestroys) {
|
if (WarnOnFinalize)
|
||||||
lock (Objects) {
|
Console.Error.WriteLine ("Unexpected finalization of " + GetType() + " instance. Consider calling Dispose.");
|
||||||
if (Objects[Handle] is ToggleRef)
|
|
||||||
PendingDestroys.Add (Objects [Handle]);
|
Dispose (false);
|
||||||
Objects.Remove (Handle);
|
|
||||||
}
|
|
||||||
if (!idle_queued){
|
|
||||||
Timeout.Add (50, new TimeoutHandler (PerformQueuedUnrefs));
|
|
||||||
idle_queued = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
|
public void Dispose ()
|
||||||
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 ()
|
|
||||||
{
|
{
|
||||||
if (disposed)
|
if (disposed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Dispose (true);
|
||||||
disposed = 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);
|
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)]
|
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
static extern IntPtr g_object_ref (IntPtr raw);
|
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)
|
public static Object GetObject(IntPtr o, bool owned_ref)
|
||||||
{
|
{
|
||||||
if (o == IntPtr.Zero)
|
if (o == IntPtr.Zero)
|
||||||
|
|
|
@ -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)]
|
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
static extern void g_object_add_toggle_ref (IntPtr raw, ToggleNotifyHandler notify_cb, IntPtr data);
|
static extern void g_object_add_toggle_ref (IntPtr raw, ToggleNotifyHandler notify_cb, IntPtr data);
|
||||||
|
|
||||||
|
|
|
@ -202,13 +202,13 @@ namespace Gtk {
|
||||||
#region Gtk.TreeIter handling
|
#region Gtk.TreeIter handling
|
||||||
ArrayList gc_handles = new ArrayList ();
|
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
|
// Free all the GCHandles pointing to the iters since they won't be garbage collected
|
||||||
foreach (System.Runtime.InteropServices.GCHandle handle in gc_handles)
|
foreach (System.Runtime.InteropServices.GCHandle handle in gc_handles)
|
||||||
handle.Free ();
|
handle.Free ();
|
||||||
|
|
||||||
base.Dispose ();
|
base.Dispose (disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void GetIter (ITreeNode node, ref TreeIter iter)
|
internal void GetIter (ITreeNode node, ref TreeIter iter)
|
||||||
|
|
|
@ -376,12 +376,12 @@ public void Path (out string path, out string path_reversed)
|
||||||
base.CreateNativeObject (names, vals);
|
base.CreateNativeObject (names, vals);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose ()
|
protected override void Dispose (bool disposing)
|
||||||
{
|
{
|
||||||
if (Handle == IntPtr.Zero)
|
if (Handle == IntPtr.Zero)
|
||||||
return;
|
return;
|
||||||
InternalDestroyed -= NativeDestroyHandler;
|
InternalDestroyed -= NativeDestroyHandler;
|
||||||
base.Dispose ();
|
base.Dispose (disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
|
Loading…
Add table
Reference in a new issue