diff --git a/ChangeLog b/ChangeLog index c1994e030..0ee544d82 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2008-01-22 Mike Kestner + + * glib/Object.cs: expose an internal ToggleRef prop. + * glib/Signal.cs: use ToggleRef for lookups instead of Object. Add + a Free method and release connections and gchandles. + * glib/ToggleRef.cs: add signal hash and release signals on free. + 2008-01-17 Mike Kestner * glib/Object.cs: remove ref from Objects hash prior to releasing it. diff --git a/glib/Object.cs b/glib/Object.cs index 147107656..a71ec8556 100644 --- a/glib/Object.cs +++ b/glib/Object.cs @@ -32,6 +32,7 @@ namespace GLib { public class Object : IWrapper, IDisposable { IntPtr handle; + ToggleRef tref; bool disposed = false; Hashtable data; static Hashtable Objects = new Hashtable(); @@ -295,14 +296,17 @@ namespace GLib { return; if (handle != IntPtr.Zero) { - ToggleRef tref = Objects [handle] as ToggleRef; Objects.Remove (handle); - if (tref != null) + if (tref != null) { tref.Free (); + tref = null; + } } handle = value; - if (value != IntPtr.Zero) - Objects [value] = new ToggleRef (this); + if (value != IntPtr.Zero) { + tref = new ToggleRef (this); + Objects [value] = tref; + } } } @@ -327,23 +331,19 @@ namespace GLib { } } + internal ToggleRef ToggleRef { + get { + return tref; + } + } + public IntPtr Handle { get { return handle; } } - Hashtable signals; - internal Hashtable Signals { - get { - if (signals == null) - signals = new Hashtable (); - return signals; - } - } - Hashtable before_signals; - [Obsolete ("Replaced by GLib.Signal marshaling mechanism.")] protected Hashtable BeforeSignals { get { diff --git a/glib/Signal.cs b/glib/Signal.cs index 84ce474f6..1d6cefde1 100644 --- a/glib/Signal.cs +++ b/glib/Signal.cs @@ -22,6 +22,7 @@ namespace GLib { using System; + using System.Collections; using System.Runtime.InteropServices; [Flags] @@ -51,19 +52,33 @@ namespace GLib { public class Signal { GCHandle gc_handle; - Object obj; + ToggleRef tref; string name; uint before_id = UInt32.MaxValue; uint after_id = UInt32.MaxValue; Delegate marshaler; + ~Signal () + { + gc_handle.Free (); + } + private Signal (GLib.Object obj, string signal_name, Delegate marshaler) { - this.obj = obj; + tref = obj.ToggleRef; name = signal_name; this.marshaler = marshaler; gc_handle = GCHandle.Alloc (this, GCHandleType.Weak); - obj.Signals [name] = this; + tref.Signals [name] = this; + } + + internal void Free () + { + DisconnectHandler (before_id); + DisconnectHandler (after_id); + before_handler = after_handler = marshaler = null; + gc_handle.Free (); + GC.SuppressFinalize (this); } public static Signal Lookup (GLib.Object obj, string name) @@ -73,7 +88,7 @@ namespace GLib { public static Signal Lookup (GLib.Object obj, string name, Delegate marshaler) { - Signal result = obj.Signals [name] as Signal; + Signal result = obj.ToggleRef.Signals [name] as Signal; if (result == null) result = new Signal (obj, name, marshaler); return result as Signal; @@ -84,7 +99,7 @@ namespace GLib { public Delegate Handler { get { - InvocationHint hint = (InvocationHint) Marshal.PtrToStructure (g_signal_get_invocation_hint (obj.Handle), typeof (InvocationHint)); + InvocationHint hint = (InvocationHint) Marshal.PtrToStructure (g_signal_get_invocation_hint (tref.Handle), typeof (InvocationHint)); if (hint.run_type == SignalFlags.RunFirst) return before_handler; else @@ -95,7 +110,7 @@ namespace GLib { uint Connect (int flags) { IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (name); - uint id = g_signal_connect_data (obj.Handle, native_name, marshaler, (IntPtr) gc_handle, IntPtr.Zero, flags); + uint id = g_signal_connect_data (tref.Handle, native_name, marshaler, (IntPtr) gc_handle, IntPtr.Zero, flags); GLib.Marshaller.Free (native_name); return id; } @@ -134,13 +149,13 @@ namespace GLib { } if (after_id == UInt32.MaxValue && before_id == UInt32.MaxValue) - obj.Signals.Remove (name); + tref.Signals.Remove (name); } void DisconnectHandler (uint handler_id) { - if (handler_id != UInt32.MaxValue && g_signal_handler_is_connected (obj.Handle, handler_id)) - g_signal_handler_disconnect (obj.Handle, handler_id); + if (handler_id != UInt32.MaxValue && g_signal_handler_is_connected (tref.Handle, handler_id)) + g_signal_handler_disconnect (tref.Handle, handler_id); } [CDeclCallback] diff --git a/glib/ToggleRef.cs b/glib/ToggleRef.cs index cee2d0d28..2cb8641ef 100644 --- a/glib/ToggleRef.cs +++ b/glib/ToggleRef.cs @@ -22,6 +22,7 @@ namespace GLib { using System; + using System.Collections; using System.Runtime.InteropServices; internal class ToggleRef { @@ -29,6 +30,7 @@ namespace GLib { IntPtr handle; object reference; GCHandle gch; + Hashtable signals; public ToggleRef (GLib.Object target) { @@ -50,6 +52,20 @@ namespace GLib { } } + public IntPtr Handle { + get { + return handle; + } + } + + public Hashtable Signals { + get { + if (signals == null) + signals = new Hashtable (); + return signals; + } + } + public GLib.Object Target { get { if (reference is GLib.Object) @@ -62,6 +78,9 @@ namespace GLib { public void Free () { + foreach (Signal s in Signals.Values) + s.Free (); + Signals.Clear (); g_object_remove_toggle_ref (handle, ToggleNotifyCallback, (IntPtr) gch); reference = null; gch.Free ();