diff --git a/cairo/Context.cs b/cairo/Context.cs index 1b8bc9e1e..9cc0000dd 100644 --- a/cairo/Context.cs +++ b/cairo/Context.cs @@ -40,6 +40,49 @@ using Cairo; namespace Cairo { + static class CairoDebug + { + static System.Collections.Generic.Dictionary traces; + + public static readonly bool Enabled; + + static CairoDebug () + { + var dbg = Environment.GetEnvironmentVariable ("MONO_CAIRO_DEBUG_DISPOSE"); + if (dbg == null) + return; + Enabled = true; + traces = new System.Collections.Generic.Dictionary (); + } + + public static void OnAllocated (IntPtr obj) + { + if (!Enabled) + throw new InvalidOperationException (); + + traces.Add (obj, Environment.StackTrace); + } + + public static void OnDisposed (IntPtr obj, bool disposing) + { + if (disposing && !Enabled) + throw new InvalidOperationException (); + + if (!disposing) { + Console.Error.WriteLine ("{0} is leaking, programmer is missing a call to Dispose", typeof(T).FullName); + if (Enabled) { + Console.Error.WriteLine ("Allocated from:"); + Console.Error.WriteLine (traces[obj]); + } else { + Console.Error.WriteLine ("Set MONO_CAIRO_DEBUG_DISPOSE to track allocation traces"); + } + } + + if (Enabled) + traces.Remove (obj); + } + } + public struct Point { public Point (int x, int y) @@ -204,12 +247,10 @@ namespace Cairo { protected virtual void Dispose (bool disposing) { - if (!disposing){ - Console.Error.WriteLine ("Cairo.Context: called from finalization thread, programmer is missing a call to Dispose"); - return; - } - - if (state == IntPtr.Zero) + if (!disposing || CairoDebug.Enabled) + CairoDebug.OnDisposed (state, disposing); + + if (!disposing|| state == IntPtr.Zero) return; //Console.WriteLine ("Destroying"); diff --git a/cairo/FontFace.cs b/cairo/FontFace.cs index b24e9dfb1..ca1de265c 100644 --- a/cairo/FontFace.cs +++ b/cairo/FontFace.cs @@ -61,13 +61,11 @@ namespace Cairo protected virtual void Dispose (bool disposing) { - if (handle == IntPtr.Zero) - return; + if (!disposing || CairoDebug.Enabled) + CairoDebug.OnDisposed (handle, disposing); - if (!disposing) { - Console.Error.WriteLine ("Cairo.FontFace: called from finalization thread, programmer is missing a call to Dispose"); + if (!disposing|| handle == IntPtr.Zero) return; - } NativeMethods.cairo_font_face_destroy (handle); handle = IntPtr.Zero; @@ -77,6 +75,8 @@ namespace Cairo public FontFace (IntPtr handle) { this.handle = handle; + if (CairoDebug.Enabled) + CairoDebug.OnAllocated (handle); } public IntPtr Handle { diff --git a/cairo/FontOptions.cs b/cairo/FontOptions.cs index fa3e84f09..c0583f10c 100644 --- a/cairo/FontOptions.cs +++ b/cairo/FontOptions.cs @@ -47,6 +47,8 @@ namespace Cairo internal FontOptions (IntPtr handle) { this.handle = handle; + if (CairoDebug.Enabled) + CairoDebug.OnAllocated (handle); } public FontOptions Copy () @@ -68,13 +70,11 @@ namespace Cairo protected virtual void Dispose (bool disposing) { - if (handle == IntPtr.Zero) - return; + if (!disposing || CairoDebug.Enabled) + CairoDebug.OnDisposed (handle, disposing); - if (!disposing) { - Console.Error.WriteLine ("Cairo.FontOptions: called from finalization thread, programmer is missing a call to Dispose"); + if (!disposing|| handle == IntPtr.Zero) return; - } NativeMethods.cairo_font_options_destroy (handle); handle = IntPtr.Zero; diff --git a/cairo/Path.cs b/cairo/Path.cs index 301ba32cd..45c9557ca 100644 --- a/cairo/Path.cs +++ b/cairo/Path.cs @@ -41,6 +41,8 @@ namespace Cairo { internal Path (IntPtr handle) { this.handle = handle; + if (CairoDebug.Enabled) + CairoDebug.OnAllocated (handle); } ~Path () @@ -57,12 +59,10 @@ namespace Cairo { protected virtual void Dispose (bool disposing) { - if (!disposing) { - Console.Error.WriteLine ("Cairo.Path: called from finalization thread, programmer is missing a call to Dispose"); - return; - } + if (!disposing || CairoDebug.Enabled) + CairoDebug.OnDisposed (handle, disposing); - if (handle == IntPtr.Zero) + if (!disposing|| handle == IntPtr.Zero) return; NativeMethods.cairo_path_destroy (handle); diff --git a/cairo/Pattern.cs b/cairo/Pattern.cs index 8a770ed92..be9c49214 100644 --- a/cairo/Pattern.cs +++ b/cairo/Pattern.cs @@ -66,12 +66,15 @@ namespace Cairo { static Hashtable patterns = new Hashtable (); - internal Pattern (IntPtr ptr) + internal Pattern (IntPtr handle) { lock (patterns){ - patterns [ptr] = this; + patterns [handle] = this; } - pattern = ptr; + + Handle = handle; + if (CairoDebug.Enabled) + CairoDebug.OnAllocated (handle); } ~Pattern () @@ -98,16 +101,14 @@ namespace Cairo { protected virtual void Dispose (bool disposing) { - if (!disposing) { - Console.Error.WriteLine ("Cairo.Pattern: called from finalization thread, programmer is missing a call to Dispose"); - return; - } + if (!disposing || CairoDebug.Enabled) + CairoDebug.OnDisposed (Handle, disposing); - if (pattern == IntPtr.Zero) + if (!disposing|| Handle == IntPtr.Zero) return; - NativeMethods.cairo_pattern_destroy (pattern); - pattern = IntPtr.Zero; + NativeMethods.cairo_pattern_destroy (Handle); + Handle = IntPtr.Zero; lock (patterns){ patterns.Remove (this); } @@ -116,7 +117,7 @@ namespace Cairo { [Obsolete ("Use Dispose()")] public void Destroy () { - Dispose (); + NativeMethods.cairo_pattern_destroy (pattern); } public Extend Extend { @@ -143,6 +144,7 @@ namespace Cairo { public IntPtr Handle { get { return pattern; } + private set { pattern = value; } } [Obsolete ("Replaced by Handle property")] diff --git a/cairo/ScaledFont.cs b/cairo/ScaledFont.cs index a15958dae..27a875db1 100644 --- a/cairo/ScaledFont.cs +++ b/cairo/ScaledFont.cs @@ -35,11 +35,13 @@ namespace Cairo { internal ScaledFont (IntPtr handle) { this.handle = handle; + if (CairoDebug.Enabled) + CairoDebug.OnAllocated (handle); } public ScaledFont (FontFace fontFace, Matrix matrix, Matrix ctm, FontOptions options) + : this (NativeMethods.cairo_scaled_font_create (fontFace.Handle, matrix, ctm, options.Handle)) { - handle = NativeMethods.cairo_scaled_font_create (fontFace.Handle, matrix, ctm, options.Handle); } ~ScaledFont () @@ -99,13 +101,11 @@ namespace Cairo { protected virtual void Dispose (bool disposing) { - if (handle == IntPtr.Zero) - return; + if (!disposing || CairoDebug.Enabled) + CairoDebug.OnDisposed (handle, disposing); - if (!disposing) { - Console.Error.WriteLine ("Cairo.ScaledFont: called from finalization thread, programmer is missing a call to Dispose"); + if (!disposing|| handle == IntPtr.Zero) return; - } NativeMethods.cairo_scaled_font_destroy (handle); handle = IntPtr.Zero; diff --git a/cairo/Surface.cs b/cairo/Surface.cs index d9369a478..52a4aee83 100644 --- a/cairo/Surface.cs +++ b/cairo/Surface.cs @@ -43,6 +43,7 @@ namespace Cairo { protected static Hashtable surfaces = new Hashtable (); internal IntPtr surface = IntPtr.Zero; + [Obsolete] protected Surface() { } @@ -55,6 +56,8 @@ namespace Cairo { } if (!owns) NativeMethods.cairo_surface_reference (ptr); + if (CairoDebug.Enabled) + CairoDebug.OnAllocated (ptr); } static internal Surface LookupExternalSurface (IntPtr p) @@ -147,13 +150,12 @@ namespace Cairo { protected virtual void Dispose (bool disposing) { - if (surface == IntPtr.Zero) - return; - if (!disposing) { - Console.Error.WriteLine ("Cairo.Surface: called from finalization thread, programmer is missing a call to Dispose"); - return; - } + if (!disposing || CairoDebug.Enabled) + CairoDebug.OnDisposed (surface, disposing); + if (!disposing|| surface == IntPtr.Zero) + return; + lock (surfaces.SyncRoot) surfaces.Remove (surface);