diff --git a/ChangeLog b/ChangeLog index 5e5e30f22..8b822fe15 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2005-02-02 Mike Kestner + + * generator/Makefile.am : remove source file. + * generator/Signal.cs : generate marshaling callbacks and use new + GLib.Signal marshaling class for events. + * generator/SignalHandler.cs : kill. byebye SignalCallback subclasses. + * glib/Makefile.am : update source files. + * glib/GLibSharp.voidObjectIntPtrSignal.cs : kill. + * glib/Object.cs : mark the old Before/After props Obsolete. Use + GLib.Signal for the notify prop methods. + * glib/Signal.cs : new signal marshaling class. It manages all the + ConnectBefore/After stuff internally and connects itself to the native + object using GCHandles and DestroyNotify lifecycle management. + * glib/SignalCallback.cs : mark Obsolete. + [Fixes #72018 and #69847] + 2005-02-01 Fredrik Nilsson * glib/Marshaller.cs : DateTime marshaling fix. diff --git a/generator/Makefile.am b/generator/Makefile.am index a0ee1a404..bdb752948 100644 --- a/generator/Makefile.am +++ b/generator/Makefile.am @@ -39,7 +39,6 @@ sources = \ Property.cs \ ReturnValue.cs \ Signal.cs \ - SignalHandler.cs \ Signature.cs \ SimpleBase.cs \ SimpleGen.cs \ diff --git a/generator/Signal.cs b/generator/Signal.cs index 50cccccdd..f16c2d777 100644 --- a/generator/Signal.cs +++ b/generator/Signal.cs @@ -34,7 +34,6 @@ namespace GtkSharp.Generation { private ReturnValue retval; private Parameters parms; private ClassBase container_type; - SignalHandler sig_handler; public Signal (XmlElement elem, ClassBase container_type) { @@ -43,7 +42,6 @@ namespace GtkSharp.Generation { retval = new ReturnValue (elem ["return-type"]); parms = new Parameters (elem["parameters"]); this.container_type = container_type; - sig_handler = new SignalHandler (elem, container_type.NS); } public string Name { @@ -57,7 +55,7 @@ namespace GtkSharp.Generation { public bool Validate () { - if (Name == "" || !sig_handler.Validate ()) { + if (Name == "") { Console.Write ("bad signal " + Name); Statistics.ThrottledCount++; return false; @@ -80,9 +78,62 @@ namespace GtkSharp.Generation { sw.WriteLine ("\t\tevent " + EventHandlerQualifiedName + " " + Name + ";"); } + private string BaseName { + get { + string result = SymbolTable.Table.GetName (retval.CType); + foreach (Parameter p in parms) { + result += p.PassAs; + if (p.Generatable is ObjectGen || p.Generatable is InterfaceGen) + result += "Object"; + else + result += SymbolTable.Table.GetName(p.CType); + } + result = result.Replace ("[]", "Array"); + return result; + } + } + + public string CName { + get { + return "\"" + elem.GetAttribute("cname") + "\""; + } + } + + public string CallbackName { + get { + return Name + "SignalCallback"; + } + } + + private string CallbackSig { + get { + string result = ""; + for (int i = 0; i < parms.Count; i++) { + if (i > 0) + result += ", "; + + if (parms[i].PassAs != "") + result += parms[i].PassAs + " "; + result += (parms[i].MarshalType + " arg" + i); + } + result += ", IntPtr gch"; + + result = result.Replace ("out ref", "out"); + result = result.Replace ("ref ref", "ref"); + + return result; + } + } + + public string DelegateName { + get { + return Name + "SignalDelegate"; + } + } + private string EventArgsName { get { - if (sig_handler.Name == "voidObjectSignal") + if (IsEventHandler) return "EventArgs"; else return Name + "Args"; @@ -91,7 +142,7 @@ namespace GtkSharp.Generation { private string EventArgsQualifiedName { get { - if (sig_handler.Name == "voidObjectSignal") + if (IsEventHandler) return "System.EventArgs"; else return container_type.NS + "." + Name + "Args"; @@ -100,7 +151,7 @@ namespace GtkSharp.Generation { private string EventHandlerName { get { - if (sig_handler.Name == "voidObjectSignal") + if (IsEventHandler) return "EventHandler"; else if (SymbolTable.Table [container_type.NS + Name + "Handler"] != null) return Name + "EventHandler"; @@ -111,13 +162,19 @@ namespace GtkSharp.Generation { private string EventHandlerQualifiedName { get { - if (sig_handler.Name == "voidObjectSignal") + if (IsEventHandler) return "System.EventHandler"; else return container_type.NS + "." + EventHandlerName; } } + public bool IsEventHandler { + get { + return retval.CSType == "void" && parms.Count == 1 && (parms [0].Generatable is ObjectGen || parms [0].Generatable is InterfaceGen); + } + } + private bool IsVoid { get { return retval.CSType == "void"; @@ -146,6 +203,52 @@ namespace GtkSharp.Generation { } } + public void GenCallback (StreamWriter sw) + { + SymbolTable table = SymbolTable.Table; + + sw.WriteLine ("\t\tdelegate " + retval.ToNativeType + " " + DelegateName + " (" + CallbackSig + ");"); + sw.WriteLine (); + sw.WriteLine ("\t\tstatic " + retval.ToNativeType + " " + CallbackName + " (" + CallbackSig + ")"); + sw.WriteLine("\t\t{"); + sw.WriteLine("\t\t\tGLib.Signal sig = ((GCHandle) gch).Target as GLib.Signal;"); + sw.WriteLine("\t\t\tif (sig == null)"); + sw.WriteLine("\t\t\t\tthrow new Exception(\"Unknown signal GC handle received \" + gch);"); + sw.WriteLine(); + sw.WriteLine("\t\t\t{0} args = new {0} ();", EventArgsQualifiedName); + if (parms.Count > 1) + sw.WriteLine("\t\t\targs.Args = new object[" + (parms.Count - 1) + "];"); + string finish = ""; + for (int idx = 1; idx < parms.Count; idx++) { + Parameter p = parms [idx]; + IGeneratable igen = p.Generatable; + if (p.PassAs == "out") + finish += "\t\t\targ" + idx + " = " + igen.ToNativeReturn ("((" + p.CSType + ")args.Args[" + (idx - 1) + "])") + ";\n"; + else if ((igen is ClassBase && !(igen is StructBase)) || igen is ManualGen) { + sw.WriteLine("\t\t\tif (arg{0} == IntPtr.Zero)", idx); + sw.WriteLine("\t\t\t\targs.Args[{0}] = null;", idx - 1); + sw.WriteLine("\t\t\telse {"); + sw.WriteLine("\t\t\t\targs.Args[" + (idx - 1) + "] = " + igen.FromNative ("arg" + idx) + ";"); + sw.WriteLine("\t\t\t}"); + } else + sw.WriteLine("\t\t\targs.Args[" + (idx - 1) + "] = " + igen.FromNative ("arg" + idx) + ";"); + } + sw.WriteLine("\t\t\t{0} handler = ({0}) sig.Handler;", EventHandlerQualifiedName); + sw.WriteLine("\t\t\thandler (GLib.Object.GetObject (arg0), args);"); + sw.WriteLine (finish); + if (!IsVoid) { + sw.WriteLine ("\t\t\tif (args.RetVal == null)"); + if (retval.CSType == "bool") + sw.WriteLine ("\t\t\t\treturn false;"); + else + sw.WriteLine ("\t\t\t\tthrow new Exception(\"args.RetVal unset in callback\");"); + + sw.WriteLine("\t\t\treturn " + table.ToNativeReturn (retval.CType, "((" + retval.CSType + ")args.RetVal)") + ";"); + } + sw.WriteLine("\t\t}"); + sw.WriteLine(); + } + private bool NeedNew (ClassBase implementor) { return elem.HasAttribute ("new_flag") || @@ -155,7 +258,7 @@ namespace GtkSharp.Generation { public void GenEventHandler (GenerationInfo gen_info) { - if (EventHandlerName == "EventHandler") + if (IsEventHandler) return; string ns = container_type.NS; @@ -233,8 +336,8 @@ namespace GtkSharp.Generation { { ImportSignature isig = new ImportSignature (parms, container_type.NS); ManagedCallString call = new ManagedCallString (parms); - sw.WriteLine ("\t\tdelegate " + retval.ToNativeType + " " + Name + "Delegate (" + isig.ToString () + ");\n"); - sw.WriteLine ("\t\tstatic {0} {1};\n", Name + "Delegate", Name + "Callback"); + sw.WriteLine ("\t\tdelegate " + retval.ToNativeType + " " + Name + "VMDelegate (" + isig.ToString () + ");\n"); + sw.WriteLine ("\t\tstatic {0} {1};\n", Name + "VMDelegate", Name + "VMCallback"); sw.WriteLine ("\t\tstatic " + retval.ToNativeType + " " + Name.ToLower() + "_cb (" + isig.ToString () + ")"); sw.WriteLine ("\t\t{"); sw.WriteLine ("\t\t\t{0} obj = GLib.Object.GetObject ({1}, false) as {0};", implementor != null ? implementor.Name : container_type.Name, parms[0].Name); @@ -245,71 +348,39 @@ namespace GtkSharp.Generation { if (!IsVoid && retval.CSType != retval.ToNativeType) sw.WriteLine ("\t\t\treturn {0};", SymbolTable.Table.ToNativeReturn (retval.CType, "raw_ret")); sw.WriteLine ("\t\t}\n"); - string cname = "\"" + elem.GetAttribute("cname") + "\""; sw.WriteLine ("\t\tprivate static void Override" + Name + " (GLib.GType gtype)"); sw.WriteLine ("\t\t{"); - sw.WriteLine ("\t\t\tif (" + Name + "Callback == null)"); - sw.WriteLine ("\t\t\t\t" + Name + "Callback = new " + Name + "Delegate (" + Name.ToLower() + "_cb);"); - sw.WriteLine ("\t\t\tOverrideVirtualMethod (gtype, " + cname + ", " + Name + "Callback);"); + sw.WriteLine ("\t\t\tif (" + Name + "VMCallback == null)"); + sw.WriteLine ("\t\t\t\t" + Name + "VMCallback = new " + Name + "VMDelegate (" + Name.ToLower() + "_cb);"); + sw.WriteLine ("\t\t\tOverrideVirtualMethod (gtype, " + CName + ", " + Name + "VMCallback);"); sw.WriteLine ("\t\t}\n"); } public void Generate (GenerationInfo gen_info, ClassBase implementor) { StreamWriter sw = gen_info.Writer; - string cname = "\"" + elem.GetAttribute("cname") + "\""; - string ns; - if (implementor == null) { - ns = container_type.NS; - GenEventHandler (gen_info); - } else - ns = implementor.NS; - sig_handler.Generate (ns, gen_info); + if (implementor == null) + GenEventHandler (gen_info); + + if (!IsEventHandler) + GenCallback (sw); GenDefaultHandlerDelegate (sw, implementor); GenVirtualMethod (sw, implementor); - string qual_marsh = ns + "Sharp." + sig_handler.Name; + string marsh = IsEventHandler ? "" : ", new " + DelegateName + "(" + CallbackName + ")"; - sw.WriteLine("\t\t[GLib.Signal("+ cname + ")]"); + sw.WriteLine("\t\t[GLib.Signal("+ CName + ")]"); sw.Write("\t\tpublic "); if (NeedNew (implementor)) sw.Write("new "); sw.WriteLine("event " + EventHandlerQualifiedName + " " + Name + " {"); sw.WriteLine("\t\t\tadd {"); - sw.WriteLine("\t\t\t\tif (value.Method.GetCustomAttributes(typeof(GLib.ConnectBeforeAttribute), false).Length > 0) {"); - sw.WriteLine("\t\t\t\t\tif (BeforeHandlers[" + cname + "] == null)"); - sw.Write("\t\t\t\t\t\tBeforeSignals[" + cname + "] = new " + qual_marsh); - sw.WriteLine("(this, " + cname + ", value, typeof (" + EventArgsQualifiedName + "), 0);"); - sw.WriteLine("\t\t\t\t\telse"); - sw.WriteLine("\t\t\t\t\t\t((GLib.SignalCallback) BeforeSignals [{0}]).AddDelegate (value);", cname); - sw.WriteLine("\t\t\t\t\tBeforeHandlers.AddHandler(" + cname + ", value);"); - sw.WriteLine("\t\t\t\t} else {"); - sw.WriteLine("\t\t\t\t\tif (AfterHandlers[" + cname + "] == null)"); - sw.Write("\t\t\t\t\t\tAfterSignals[" + cname + "] = new " + qual_marsh); - sw.WriteLine("(this, " + cname + ", value, typeof (" + EventArgsQualifiedName + "), 1);"); - sw.WriteLine("\t\t\t\t\telse"); - sw.WriteLine("\t\t\t\t\t\t((GLib.SignalCallback) AfterSignals [{0}]).AddDelegate (value);", cname); - sw.WriteLine("\t\t\t\t\tAfterHandlers.AddHandler(" + cname + ", value);"); - sw.WriteLine("\t\t\t\t}"); + sw.WriteLine("\t\t\t\tGLib.Signal sig = GLib.Signal.Lookup (this, " + CName + marsh + ");"); + sw.WriteLine("\t\t\t\tsig.AddDelegate (value);"); sw.WriteLine("\t\t\t}"); sw.WriteLine("\t\t\tremove {"); - sw.WriteLine("\t\t\t\tSystem.ComponentModel.EventHandlerList event_list = AfterHandlers;"); - sw.WriteLine("\t\t\t\tHashtable signals = AfterSignals;"); - sw.WriteLine("\t\t\t\tif (value.Method.GetCustomAttributes(typeof(GLib.ConnectBeforeAttribute), false).Length > 0) {"); - sw.WriteLine("\t\t\t\t\tevent_list = BeforeHandlers;"); - sw.WriteLine("\t\t\t\t\tsignals = BeforeSignals;"); - sw.WriteLine("\t\t\t\t}"); - sw.WriteLine("\t\t\t\tGLib.SignalCallback cb = signals [{0}] as GLib.SignalCallback;", cname); - sw.WriteLine("\t\t\t\tevent_list.RemoveHandler(" + cname + ", value);"); - sw.WriteLine("\t\t\t\tif (cb == null)"); - sw.WriteLine("\t\t\t\t\treturn;"); - sw.WriteLine(); - sw.WriteLine("\t\t\t\tcb.RemoveDelegate (value);"); - sw.WriteLine(); - sw.WriteLine("\t\t\t\tif (event_list[" + cname + "] == null) {"); - sw.WriteLine("\t\t\t\t\tsignals.Remove(" + cname + ");"); - sw.WriteLine("\t\t\t\t\tcb.Dispose ();"); - sw.WriteLine("\t\t\t\t}"); + sw.WriteLine("\t\t\t\tGLib.Signal sig = GLib.Signal.Lookup (this, " + CName + marsh + ");"); + sw.WriteLine("\t\t\t\tsig.RemoveDelegate (value);"); sw.WriteLine("\t\t\t}"); sw.WriteLine("\t\t}"); sw.WriteLine(); diff --git a/generator/SignalHandler.cs b/generator/SignalHandler.cs deleted file mode 100644 index d1630aa37..000000000 --- a/generator/SignalHandler.cs +++ /dev/null @@ -1,211 +0,0 @@ -// GtkSharp.Generation.SignalHandler.cs - The SignalHandler marshaling Class. -// -// Author: Mike Kestner -// -// Copyright (c) 2002-2003 Mike Kestner -// Copyright (c) 2004 Novell, Inc. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// General Public License for more details. -// -// You should have received a copy of the GNU General Public -// License along with this program; if not, write to the -// Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. - - -namespace GtkSharp.Generation { - - using System; - using System.IO; - using System.Xml; - - public class SignalHandler { - - XmlElement sig; - string ns; - ReturnValue retval; - Parameters parms = null; - - public SignalHandler (XmlElement sig, string ns) - { - this.sig = sig; - this.ns = ns; - retval = new ReturnValue (sig["return-type"]); - parms = new Parameters (sig ["parameters"]); - } - - public bool Validate () - { - if (!retval.Validate ()) { - Console.Write(" in signal handler " + Name); - return false; - } - - if (!parms.Validate ()) { - Console.Write("Missing parameters "); - return false; - } - - return true; - } - - private string ISig { - get { - string result = ""; - for (int i = 0; i < parms.Count; i++) { - if (i > 0) - result += ", "; - - if (parms[i].PassAs != "") - result += parms[i].PassAs + " "; - result += (parms[i].MarshalType + " arg" + i); - } - - result = result.Replace ("out ref", "out"); - result = result.Replace ("ref ref", "ref"); - - return result; - } - } - - private string BaseName { - get { - string result = SymbolTable.Table.GetName (retval.CType); - foreach (Parameter p in parms) { - result += p.PassAs; - if (p.Generatable is ObjectGen || p.Generatable is InterfaceGen) { - result += "Object"; - } else { - result += SymbolTable.Table.GetName(p.CType); - } - } - result = result.Replace ("[]", "Array"); - return result; - } - } - - public string CallbackName { - get { - return BaseName + "Callback"; - } - } - - public string DelegateName { - get { - return BaseName + "Delegate"; - } - } - - public string Name { - get { - return BaseName + "Signal"; - } - } - - public void Generate (string implementor_ns, GenerationInfo gen_info) - { - SymbolTable table = SymbolTable.Table; - - StreamWriter sw = gen_info.OpenStream (implementor_ns + "Sharp." + Name); - - sw.WriteLine("namespace " + implementor_ns + "Sharp {"); - sw.WriteLine(); - sw.WriteLine("\tusing System;"); - sw.WriteLine("\tusing System.Runtime.InteropServices;"); - sw.WriteLine(); - sw.Write("\tinternal delegate " + retval.ToNativeType + " "); - sw.WriteLine(DelegateName + "(" + ISig + ", int key);"); - sw.WriteLine(); - sw.WriteLine("\tinternal class " + Name + " : GLib.SignalCallback {"); - sw.WriteLine(); - sw.WriteLine("\t\tprivate static " + DelegateName + " _Delegate;"); - sw.WriteLine(); - sw.Write("\t\tprivate static " + retval.ToNativeType + " "); - sw.WriteLine(CallbackName + "(" + ISig + ", int key)"); - sw.WriteLine("\t\t{"); - sw.WriteLine("\t\t\tif (!_Instances.Contains(key))"); - sw.WriteLine("\t\t\t\tthrow new Exception(\"Unexpected signal key \" + key);"); - sw.WriteLine(); - sw.WriteLine("\t\t\t" + Name + " inst = (" + Name + ") _Instances[key];"); - if ((retval.CSType == "void") && (parms.Count == 1)) { - sw.WriteLine("\t\t\tEventHandler h = (EventHandler) inst._handler;"); - sw.WriteLine("\t\t\th (inst._obj, new EventArgs ());"); - sw.WriteLine("\t\t}"); - sw.WriteLine(); - } else { - sw.WriteLine("\t\t\tGLib.SignalArgs args = (GLib.SignalArgs) Activator.CreateInstance (inst._argstype);"); - if (parms.Count > 1) { - sw.WriteLine("\t\t\targs.Args = new object[" + (parms.Count-1) + "];"); - } - for (int idx=1; idx < parms.Count; idx++) { - if (parms[idx].PassAs == "out") - continue; - - string ctype = parms[idx].CType; - ClassBase wrapper = table.GetClassGen (ctype); - if ((wrapper != null && !(wrapper is StructBase)) || table.IsManuallyWrapped (ctype)) { - sw.WriteLine("\t\t\tif (arg{0} == IntPtr.Zero)", idx); - sw.WriteLine("\t\t\t\targs.Args[{0}] = null;", idx - 1); - sw.WriteLine("\t\t\telse {"); - if ((wrapper != null) && wrapper is ObjectGen) - sw.WriteLine("\t\t\t\targs.Args[" + (idx-1) + "] = GLib.Object.GetObject(arg" + idx + ");"); - else - sw.WriteLine("\t\t\t\targs.Args[" + (idx-1) + "] = " + table.FromNative (ctype, "arg" + idx) + ";"); - sw.WriteLine("\t\t\t}"); - } else { - sw.WriteLine("\t\t\targs.Args[" + (idx-1) + "] = " + table.FromNative (ctype, "arg" + idx) + ";"); - } - } - sw.WriteLine("\t\t\tobject[] argv = new object[2];"); - sw.WriteLine("\t\t\targv[0] = inst._obj;"); - sw.WriteLine("\t\t\targv[1] = args;"); - sw.WriteLine("\t\t\tinst._handler.DynamicInvoke(argv);"); - for (int idx=1; idx < parms.Count; idx++) { - if (parms[idx].PassAs != "") { - sw.WriteLine ("\t\t\targ" + idx + " = " + table.ToNativeReturn (parms[idx].CType, "((" + parms[idx].CSType + ")args.Args[" + (idx - 1) + "])") + ";"); - } - } - if (retval.CSType != "void") { - sw.WriteLine ("\t\t\tif (args.RetVal == null)"); - if (retval.CSType == "bool") - sw.WriteLine ("\t\t\t\treturn false;"); - else - sw.WriteLine ("\t\t\t\tthrow new Exception(\"args.RetVal unset in callback\");"); - - sw.WriteLine("\t\t\treturn " + table.ToNativeReturn (retval.CType, "((" + retval.CSType + ")args.RetVal)") + ";"); - } - sw.WriteLine("\t\t}"); - sw.WriteLine(); - } - sw.Write("\t\tpublic " + Name + "(GLib.Object obj, "); - sw.WriteLine("string name, Delegate eh, Type argstype, int connect_flags) : base(obj, eh, argstype)"); - sw.WriteLine("\t\t{"); - sw.WriteLine("\t\t\tif (_Delegate == null) {"); - sw.WriteLine("\t\t\t\t_Delegate = new " + DelegateName + "(" + CallbackName + ");"); - sw.WriteLine("\t\t\t}"); - sw.WriteLine("\t\t\tConnect (name, _Delegate, connect_flags);"); - sw.WriteLine("\t\t}"); - sw.WriteLine(); - sw.WriteLine("\t\tprotected override void Dispose (bool disposing)"); - sw.WriteLine("\t\t{"); - sw.WriteLine("\t\t\t_Instances.Remove(_key);"); - sw.WriteLine("\t\t\tif(_Instances.Count == 0)"); - sw.WriteLine("\t\t\t\t_Delegate = null;"); - sw.WriteLine(); - sw.WriteLine("\t\t\tDisconnect ();"); - sw.WriteLine("\t\t\tbase.Dispose (disposing);"); - sw.WriteLine("\t\t}"); - sw.WriteLine("\t}"); - sw.WriteLine("}"); - sw.Close(); - } - } -} - diff --git a/glib/GLibSharp.voidObjectIntPtrSignal.cs b/glib/GLibSharp.voidObjectIntPtrSignal.cs deleted file mode 100644 index 6097a85ab..000000000 --- a/glib/GLibSharp.voidObjectIntPtrSignal.cs +++ /dev/null @@ -1,50 +0,0 @@ -// copied from gtk/generated/GtkSharp.voidObjectIntPtrSignal.cs and renamespaced - -// This file was generated by the Gtk# code generator. -// Any changes made will be lost if regenerated. - -namespace GLibSharp { - - using System; - using System.Runtime.InteropServices; - - internal delegate void voidObjectIntPtrDelegate(IntPtr arg0, IntPtr arg1, int key); - - internal class voidObjectIntPtrSignal : GLib.SignalCallback { - - private static voidObjectIntPtrDelegate _Delegate; - - private static void voidObjectIntPtrCallback(IntPtr arg0, IntPtr arg1, int key) - { - if (!_Instances.Contains(key)) - throw new Exception("Unexpected signal key " + key); - - voidObjectIntPtrSignal inst = (voidObjectIntPtrSignal) _Instances[key]; - GLib.SignalArgs args = (GLib.SignalArgs) Activator.CreateInstance (inst._argstype); - args.Args = new object[1]; - args.Args[0] = arg1; - object[] argv = new object[2]; - argv[0] = inst._obj; - argv[1] = args; - inst._handler.DynamicInvoke(argv); - } - - public voidObjectIntPtrSignal(GLib.Object obj, string name, Delegate eh, Type argstype, int connect_flags) : base(obj, eh, argstype) - { - if (_Delegate == null) { - _Delegate = new voidObjectIntPtrDelegate(voidObjectIntPtrCallback); - } - Connect (name, _Delegate, connect_flags); - } - - protected override void Dispose (bool disposing) - { - _Instances.Remove(_key); - if(_Instances.Count == 0) - _Delegate = null; - - Disconnect (); - base.Dispose (disposing); - } - } -} diff --git a/glib/Makefile.am b/glib/Makefile.am index 141df3813..85b62d6a6 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -19,7 +19,6 @@ sources = \ EnumWrapper.cs \ FileUtils.cs \ GException.cs \ - GLibSharp.voidObjectIntPtrSignal.cs \ GString.cs \ Idle.cs \ IWrapper.cs \ @@ -37,6 +36,7 @@ sources = \ ObjectManager.cs \ Opaque.cs \ PropertyAttribute.cs \ + Signal.cs \ SignalArgs.cs \ SignalAttribute.cs \ SignalCallback.cs \ diff --git a/glib/Object.cs b/glib/Object.cs index 4ae68b2a7..ae2fbc78b 100644 --- a/glib/Object.cs +++ b/glib/Object.cs @@ -245,6 +245,8 @@ namespace GLib { } Hashtable before_signals; + + [Obsolete ("Replaced by GLib.Signal marshaling mechanism.")] protected Hashtable BeforeSignals { get { if (before_signals == null) @@ -254,6 +256,7 @@ namespace GLib { } Hashtable after_signals; + [Obsolete ("Replaced by GLib.Signal marshaling mechanism.")] protected Hashtable AfterSignals { get { if (after_signals == null) @@ -263,6 +266,7 @@ namespace GLib { } EventHandlerList before_handlers; + [Obsolete ("Replaced by GLib.Signal marshaling mechanism.")] protected EventHandlerList BeforeHandlers { get { if (before_handlers == null) @@ -272,6 +276,7 @@ namespace GLib { } EventHandlerList after_handlers; + [Obsolete ("Replaced by GLib.Signal marshaling mechanism.")] protected EventHandlerList AfterHandlers { get { if (after_handlers == null) @@ -280,13 +285,25 @@ namespace GLib { } } + delegate void NotifyDelegate (IntPtr handle, IntPtr pspec, IntPtr gch); + + void NotifyCallback (IntPtr handle, IntPtr pspec, IntPtr gch) + { + GLib.Signal sig = ((GCHandle) gch).Target as GLib.Signal; + if (sig == null) + throw new Exception("Unknown signal GC handle received " + gch); + + NotifyArgs args = new NotifyArgs (); + args.Args = new object[1]; + args.Args[0] = pspec; + NotifyHandler handler = (NotifyHandler) sig.Handler; + handler (GLib.Object.GetObject (handle), args); + } + void ConnectNotification (string signal, NotifyHandler handler) { - if (AfterHandlers[signal] == null) - AfterSignals[signal] = new GLibSharp.voidObjectIntPtrSignal (this, signal, handler, typeof (NotifyArgs), 1); - else - ((GLib.SignalCallback) AfterSignals[signal]).AddDelegate (handler); - AfterHandlers.AddHandler (signal, handler); + Signal sig = Signal.Lookup (this, signal, new NotifyDelegate (NotifyCallback)); + sig.AddDelegate (handler); } public void AddNotification (string property, NotifyHandler handler) @@ -301,17 +318,8 @@ namespace GLib { void DisconnectNotification (string signal, NotifyHandler handler) { - GLib.SignalCallback cb = AfterSignals[signal] as GLib.SignalCallback; - AfterHandlers.RemoveHandler (signal, handler); - - if (cb == null) - return; - cb.RemoveDelegate (handler); - - if (AfterHandlers[signal] == null) { - AfterSignals.Remove (signal); - cb.Dispose (); - } + Signal sig = Signal.Lookup (this, signal, new NotifyDelegate (NotifyCallback)); + sig.RemoveDelegate (handler); } public void RemoveNotification (string property, NotifyHandler handler) diff --git a/glib/Signal.cs b/glib/Signal.cs new file mode 100644 index 000000000..749f91652 --- /dev/null +++ b/glib/Signal.cs @@ -0,0 +1,193 @@ +// GLib.Signal.cs - signal marshaling class +// +// Authors: Mike Kestner +// +// Copyright (c) 2005 Novell, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the Lesser GNU General +// Public License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + + +namespace GLib { + + using System; + using System.Runtime.InteropServices; + + [Flags] + internal enum SignalFlags { + RunFirst = 1 << 0, + RunLast = 1 << 1, + RunCleanup = 1 << 2, + NoRecurse = 1 << 3, + Detailed = 1 << 4, + Action = 1 << 5, + NoHooks = 1 << 6 + } + + [StructLayout (LayoutKind.Sequential)] + internal struct InvocationHint { + public uint signal_id; + public uint detail; + public SignalFlags run_type; + } + + public class Signal { + + GCHandle gc_handle; + IntPtr handle; + string name; + uint before_id = UInt32.MaxValue; + uint after_id = UInt32.MaxValue; + Delegate marshaler; + + static DestroyNotify notify = new DestroyNotify (OnNativeDestroy); + delegate void DestroyNotify (IntPtr data, IntPtr obj); + static void OnNativeDestroy (IntPtr data, IntPtr obj) + { + GCHandle gch = (GCHandle) data; + Signal s = gch.Target as Signal; + s.DisconnectHandler (s.before_id); + s.DisconnectHandler (s.after_id); + gch.Free (); + } + + private Signal (GLib.Object obj, string signal_name, Delegate marshaler) + { + handle = obj.Handle; + name = signal_name; + this.marshaler = marshaler; + gc_handle = GCHandle.Alloc (this); + g_object_set_data_full (handle, name + "_signal_marshaler", (IntPtr) gc_handle, notify); + } + + public static Signal Lookup (GLib.Object obj, string name) + { + return Lookup (obj, name, EventHandlerDelegate); + } + + public static Signal Lookup (GLib.Object obj, string name, Delegate marshaler) + { + IntPtr data = g_object_get_data (obj.Handle, name + "_signal_marshaler"); + if (data == IntPtr.Zero) + return new Signal (obj, name, marshaler); + + GCHandle gch = (GCHandle) data; + return gch.Target as Signal; + } + + Delegate before_handler; + Delegate after_handler; + + public Delegate Handler { + get { + InvocationHint hint = (InvocationHint) Marshal.PtrToStructure (g_signal_get_invocation_hint (handle), typeof (InvocationHint)); + if (hint.run_type == SignalFlags.RunFirst) + return before_handler; + else + return after_handler; + } + } + + public void AddDelegate (Delegate d) + { + if (d.Method.IsDefined (typeof (ConnectBeforeAttribute), false)) { + if (before_handler == null) { + before_handler = d; + before_id = g_signal_connect_data (handle, name, marshaler, (IntPtr) gc_handle, IntPtr.Zero, 0); + } else + before_handler = Delegate.Combine (before_handler, d); + } else { + if (after_handler == null) { + after_handler = d; + after_id = g_signal_connect_data (handle, name, marshaler, (IntPtr) gc_handle, IntPtr.Zero, 1); + } else + after_handler = Delegate.Combine (after_handler, d); + } + } + + public void RemoveDelegate (Delegate d) + { + if (d.Method.IsDefined (typeof (ConnectBeforeAttribute), false)) { + before_handler = Delegate.Remove (before_handler, d); + if (before_handler == null) { + DisconnectHandler (before_id); + before_id = UInt32.MaxValue; + } + } else { + after_handler = Delegate.Remove (after_handler, d); + if (after_handler == null) { + DisconnectHandler (after_id); + after_id = UInt32.MaxValue; + } + } + + if (after_id == UInt32.MaxValue && before_id == UInt32.MaxValue) + DisconnectObject (); + } + + void DisconnectObject () + { + g_object_set_data (handle, name + "_signal_marshaler", IntPtr.Zero); + } + + void DisconnectHandler (uint handler_id) + { + if (handler_id != UInt32.MaxValue && g_signal_handler_is_connected (handle, handler_id)) + g_signal_handler_disconnect (handle, handler_id); + } + + delegate void voidObjectDelegate (IntPtr handle, IntPtr gch); + + static void voidObjectCallback (IntPtr handle, IntPtr gch) + { + Signal sig = ((GCHandle) gch).Target as Signal; + if (sig == null) + throw new Exception ("Unknown signal class GC handle received."); + + EventHandler handler = (EventHandler) sig.Handler; + handler (Object.GetObject (handle), EventArgs.Empty); + } + + static voidObjectDelegate event_handler_delegate; + static voidObjectDelegate EventHandlerDelegate { + get { + if (event_handler_delegate == null) + event_handler_delegate = new voidObjectDelegate (voidObjectCallback); + return event_handler_delegate; + } + } + + [DllImport("libgobject-2.0-0.dll")] + static extern IntPtr g_object_get_data (IntPtr instance, string key); + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_object_set_data (IntPtr instance, string key, IntPtr data); + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_object_set_data_full (IntPtr instance, string key, IntPtr data, DestroyNotify notify); + + [DllImport("libgobject-2.0-0.dll")] + static extern uint g_signal_connect_data(IntPtr obj, string name, Delegate cb, IntPtr gc_handle, IntPtr dummy, int flags); + + [DllImport("libgobject-2.0-0.dll")] + static extern IntPtr g_signal_get_invocation_hint (IntPtr instance); + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_signal_handler_disconnect (IntPtr instance, uint handler); + + [DllImport("libgobject-2.0-0.dll")] + static extern bool g_signal_handler_is_connected (IntPtr instance, uint handler); + } +} + diff --git a/glib/SignalCallback.cs b/glib/SignalCallback.cs index 357fc6bd0..b1142020b 100644 --- a/glib/SignalCallback.cs +++ b/glib/SignalCallback.cs @@ -25,6 +25,7 @@ namespace GLib { using System.Collections; using System.Runtime.InteropServices; + [Obsolete ("Replaced by GLib.Signal.")] public abstract class SignalCallback : IDisposable { // A counter used to produce unique keys for instances.