From 38219387642a98cf5c054be57a761e4a1d369f26 Mon Sep 17 00:00:00 2001 From: Gonzalo Paniagua Javier Date: Sun, 6 Apr 2003 09:21:15 +0000 Subject: [PATCH] 2003-04-03 Gonzalo Paniagua Javier * generator/CallbackGen.cs: the new generated wrappers have: -(optional) Field of the same type returned by the callback. -A call to RemoveIfNotAlive at the beginning. It returns true, return the dummy field. -Added an object to the ctor signature and pass it to the base class. * generator/Ctor.cs: added a Params property. * generator/Method.cs: set Static property in Parameters if the method is static. * generator/Parameters.cs: added Static property. The call creation of the delegate wrapper (if applicable) uses the new signature. Pass a null as object is the method is static. * generator/StructBase.cs: set Static for the parameters of the ctors. * glib/DelegateWrapper.cs: the ctor takes an object (the one creating the wrapper or null) and creates a weak reference to it. Store it in a static Hashtable (this way the wrapper itself is not garbage collected). (RemoveIfNotAlive): called from the native delegate callbacks. If the target of the weak reference has been garbage collected, removes itself from the hashtable to let the GC dispose this instance and returns true. * gdk/Pixbuf.custom: * gtk/Clipboard.custom: * gtk/GtkSharp.GtkClipboardClearFuncNative.cs: * gtk/GtkSharp.GtkClipboardGetFuncNative.cs: * glade/XML.custom: changed delegate wrappers to match the new signature. svn path=/trunk/gtk-sharp/; revision=13237 --- gdk/Pixbuf.custom | 2 +- generator/CallbackGen.cs | 24 ++++++++++-- generator/Ctor.cs | 4 ++ generator/Method.cs | 1 + generator/Parameters.cs | 7 +++- generator/StructBase.cs | 3 ++ glade/XML.custom | 2 +- glib/DelegateWrapper.cs | 41 +++++++++++++++++++-- gtk/Clipboard.custom | 4 +- gtk/GtkSharp.GtkClipboardClearFuncNative.cs | 3 +- gtk/GtkSharp.GtkClipboardGetFuncNative.cs | 3 +- 11 files changed, 80 insertions(+), 14 deletions(-) diff --git a/gdk/Pixbuf.custom b/gdk/Pixbuf.custom index 547871833..89c86c42d 100644 --- a/gdk/Pixbuf.custom +++ b/gdk/Pixbuf.custom @@ -82,7 +82,7 @@ public Pixbuf(byte [] data, bool has_alpha, int bits_per_sample, int width, int height, int rowstride, Gdk.PixbufDestroyNotify destroy_fn) { GdkSharp.PixbufDestroyNotifyWrapper destroy_fn_wrapper = null; - destroy_fn_wrapper = new GdkSharp.PixbufDestroyNotifyWrapper (destroy_fn); + destroy_fn_wrapper = new GdkSharp.PixbufDestroyNotifyWrapper (destroy_fn, this); Raw = gdk_pixbuf_new_from_data(data, (int) Gdk.Colorspace.Rgb, has_alpha, bits_per_sample, width, height, rowstride, destroy_fn_wrapper.NativeDelegate, IntPtr.Zero); } diff --git a/generator/CallbackGen.cs b/generator/CallbackGen.cs index 6edb3f69a..cd1aec50d 100644 --- a/generator/CallbackGen.cs +++ b/generator/CallbackGen.cs @@ -84,15 +84,34 @@ namespace GtkSharp.Generation { XmlElement ret_elem = Elem["return-type"]; string rettype = ret_elem.GetAttribute("type"); string m_ret = SymbolTable.GetMarshalReturnType (rettype); + ClassBase ret_wrapper = SymbolTable.GetClassGen (rettype); sw.WriteLine ("\tpublic delegate " + m_ret + " " + wrapper + "(" + import_sig + ");"); sw.WriteLine (); sw.WriteLine ("\tpublic class " + Name + "Wrapper : GLib.DelegateWrapper {"); + if (m_ret != "void") { + if (SymbolTable.IsEnum (rettype)) { + sw.WriteLine ("\t\tstatic int _dummy;"); + } else if (ret_wrapper != null && (ret_wrapper is ObjectGen || ret_wrapper is OpaqueGen)) { + // Do nothing + } else if (!SymbolTable.IsStruct (rettype) && !SymbolTable.IsBoxed (rettype)) { + sw.WriteLine ("\t\tstatic {0} _dummy;", s_ret); + } + } + sw.WriteLine (); sw.WriteLine ("\t\tpublic " + m_ret + " NativeCallback (" + import_sig + ")"); sw.WriteLine ("\t\t{"); + sw.Write ("\t\t\tif (RemoveIfNotAlive ()) return "); + if (SymbolTable.IsStruct (rettype) || SymbolTable.IsBoxed (rettype)) + sw.WriteLine ("IntPtr.Zero;"); + else if (ret_wrapper != null && (ret_wrapper is ObjectGen || ret_wrapper is OpaqueGen)) + sw.WriteLine ("IntPtr.Zero;"); + else + sw.WriteLine (m_ret != "void" ? "_dummy;" : ";"); + int count = (parms != null) ? parms.Count : 0; if (count > 0) sw.WriteLine ("\t\t\tobject[] _args = new object[{0}];", count); @@ -129,8 +148,7 @@ namespace GtkSharp.Generation { sw.Write ("\t\t\t"); string invoke = "_managed (" + call_str + ")"; if (m_ret != "void") { - ClassBase parm_wrapper = SymbolTable.GetClassGen (rettype); - if (parm_wrapper != null && (parm_wrapper is ObjectGen || parm_wrapper is OpaqueGen)) + if (ret_wrapper != null && (ret_wrapper is ObjectGen || ret_wrapper is OpaqueGen)) sw.WriteLine ("return (({0}) {1}).Handle;", s_ret, invoke); else if (SymbolTable.IsStruct (rettype) || SymbolTable.IsBoxed (rettype)) { // Shoot. I have no idea what to do here. @@ -150,7 +168,7 @@ namespace GtkSharp.Generation { sw.WriteLine ("\t\tprotected {0} _managed;", NS + "." + Name); sw.WriteLine (); - sw.WriteLine ("\t\tpublic {0} ({1} managed) : base ()", Name + "Wrapper", NS + "." + Name); + sw.WriteLine ("\t\tpublic {0} ({1} managed, object o) : base (o)", Name + "Wrapper", NS + "." + Name); sw.WriteLine ("\t\t{"); sw.WriteLine ("\t\t\tNativeDelegate = new {0} (NativeCallback);", wrapper); diff --git a/generator/Ctor.cs b/generator/Ctor.cs index 2e8178d68..9c99eaa0b 100644 --- a/generator/Ctor.cs +++ b/generator/Ctor.cs @@ -31,6 +31,10 @@ namespace GtkSharp.Generation { set { force_static = value; } } + public Parameters Params { + get { return parms; } + } + public Ctor (string libname, XmlElement elem, ClassBase container_type) { this.libname = libname; this.elem = elem; diff --git a/generator/Method.cs b/generator/Method.cs index 3ba0c2ae2..7846d2408 100644 --- a/generator/Method.cs +++ b/generator/Method.cs @@ -170,6 +170,7 @@ namespace GtkSharp.Generation { is_set = ((parms != null && (parms.IsAccessor || (parms.Count == 1 && s_ret == "void"))) && (Name.Length > 3 && Name.Substring(0, 3) == "Set")); if (parms != null) { + parms.Static = is_shared; parms.CreateSignature (is_set); sig = "(" + parms.Signature + ")"; isig = "(" + (is_shared ? "" : container_type.MarshalType + " raw, ") + parms.ImportSig + ");"; diff --git a/generator/Parameters.cs b/generator/Parameters.cs index 1a140dd74..bc4b06885 100644 --- a/generator/Parameters.cs +++ b/generator/Parameters.cs @@ -123,6 +123,7 @@ namespace GtkSharp.Generation { private string signature; private string signature_types; private bool hide_data; + private bool is_static; public Parameters (XmlElement elem) { @@ -169,6 +170,10 @@ namespace GtkSharp.Generation { set { hide_data = value; } } + public bool Static { + set { is_static = value; } + } + public bool Validate () { foreach (XmlNode parm in elem.ChildNodes) { @@ -394,7 +399,7 @@ namespace GtkSharp.Generation { { sw.Write ("if ({0} != null) ", name); } - sw.WriteLine ("{1}_wrapper = new {0} ({1});", type, name); + sw.WriteLine ("{1}_wrapper = new {0} ({1}, {2});", type, name, is_static ? "null" : "this"); } } } diff --git a/generator/StructBase.cs b/generator/StructBase.cs index 534e1f063..17e210813 100644 --- a/generator/StructBase.cs +++ b/generator/StructBase.cs @@ -262,7 +262,10 @@ namespace GtkSharp.Generation { foreach (Ctor ctor in Ctors) { ctor.ForceStatic = true; + if (ctor.Params != null) + ctor.Params.Static = true; } + base.GenCtors (sw); } diff --git a/glade/XML.custom b/glade/XML.custom index e9ed4ac21..b9f0845f6 100644 --- a/glade/XML.custom +++ b/glade/XML.custom @@ -18,7 +18,7 @@ static public void SetCustomHandler (Glade.XMLCustomWidgetHandler handler) { - callback_wrapper = new GladeSharp.XMLCustomWidgetHandlerWrapper (handler); + callback_wrapper = new GladeSharp.XMLCustomWidgetHandlerWrapper (handler, null); glade_set_custom_handler (callback_wrapper.NativeDelegate, IntPtr.Zero); } diff --git a/glib/DelegateWrapper.cs b/glib/DelegateWrapper.cs index e00fa4b34..4fc757847 100644 --- a/glib/DelegateWrapper.cs +++ b/glib/DelegateWrapper.cs @@ -1,8 +1,11 @@ // DelegateWrapper.cs - Delegate wrapper implementation // -// Author: Rachel Hestilow +// Authors: +// Rachel Hestilow +// Gonzalo Panigua Javier // // (c) 2002 Rachel Hestilow +// (c) 2003 Ximian, Inc. (http://www.ximian.com) namespace GLib { @@ -17,10 +20,40 @@ namespace GLib { /// Wrapper class for delegates. /// - public class DelegateWrapper { - static ArrayList _instances = new ArrayList (); + public class DelegateWrapper + { + // Keys in the hashtable are instances of classes derived from this one. + // Values are WeakReference instances to the object that creates the + // delegate or instances of derived classes (if created from static methods). + static Hashtable weakReferences = new Hashtable (); + + // The object 'o' is the object that creates the instance of the DelegateWrapper + // derived class or null if created from a static method. + // Note that the instances will never be disposed if they are created in a static + // method. + protected DelegateWrapper (object o) + { + if (o == null) + o = this; // Never expires. Used in static methods. - protected DelegateWrapper () { + weakReferences [this] = new WeakReference (o); + } + + // IMPORTANT: this method must be the first one called from the callback methods that + // are invoked from unmanaged code. + // If this method returns true, the object that created the delegate wrapper no longer + // exists and the instance of the delegate itself is removed from the hash table. + protected bool RemoveIfNotAlive () + { + WeakReference r = null; + r = weakReferences [this] as WeakReference; + if (r != null && !r.IsAlive) { + weakReferences.Remove (this); + r = null; + } + + return (r == null); } } } + diff --git a/gtk/Clipboard.custom b/gtk/Clipboard.custom index 85ef5e058..9e3f03fdd 100644 --- a/gtk/Clipboard.custom +++ b/gtk/Clipboard.custom @@ -32,8 +32,8 @@ clipboard_objects[this_id] = data; } - get_func_wrapper = new GtkSharp.GtkClipboardGetFuncWrapper (get_func); - clear_func_wrapper = new GtkSharp.GtkClipboardClearFuncWrapper (clear_func); + get_func_wrapper = new GtkSharp.GtkClipboardGetFuncWrapper (get_func, this); + clear_func_wrapper = new GtkSharp.GtkClipboardClearFuncWrapper (clear_func, this); IntPtr list = IntPtr.Zero; diff --git a/gtk/GtkSharp.GtkClipboardClearFuncNative.cs b/gtk/GtkSharp.GtkClipboardClearFuncNative.cs index 58f7450fc..b38d0bdd0 100644 --- a/gtk/GtkSharp.GtkClipboardClearFuncNative.cs +++ b/gtk/GtkSharp.GtkClipboardClearFuncNative.cs @@ -9,6 +9,7 @@ namespace GtkSharp { public void NativeCallback (IntPtr clipboard, uint objid) { + if (RemoveIfNotAlive ()) return; object[] _args = new object[2]; _args[0] = (Gtk.Clipboard) GLib.Opaque.GetOpaque(clipboard); if (_args[0] == null) @@ -21,7 +22,7 @@ namespace GtkSharp { public GtkClipboardClearFuncNative NativeDelegate; protected Gtk.ClipboardClearFunc _managed; - public GtkClipboardClearFuncWrapper (Gtk.ClipboardClearFunc managed) : base () + public GtkClipboardClearFuncWrapper (Gtk.ClipboardClearFunc managed, object o) : base (o) { NativeDelegate = new GtkClipboardClearFuncNative (NativeCallback); _managed = managed; diff --git a/gtk/GtkSharp.GtkClipboardGetFuncNative.cs b/gtk/GtkSharp.GtkClipboardGetFuncNative.cs index df5633091..838701537 100644 --- a/gtk/GtkSharp.GtkClipboardGetFuncNative.cs +++ b/gtk/GtkSharp.GtkClipboardGetFuncNative.cs @@ -9,6 +9,7 @@ namespace GtkSharp { public void NativeCallback (IntPtr clipboard, ref Gtk.SelectionData selection_data, uint info, uint obj_id) { + if (RemoveIfNotAlive ()) return; object[] _args = new object[4]; _args[0] = (Gtk.Clipboard) GLib.Opaque.GetOpaque(clipboard); if (_args[0] == null) @@ -23,7 +24,7 @@ namespace GtkSharp { public GtkClipboardGetFuncNative NativeDelegate; protected Gtk.ClipboardGetFunc _managed; - public GtkClipboardGetFuncWrapper (Gtk.ClipboardGetFunc managed) : base () + public GtkClipboardGetFuncWrapper (Gtk.ClipboardGetFunc managed, object o) : base (o) { NativeDelegate = new GtkClipboardGetFuncNative (NativeCallback); _managed = managed;