2005-02-02 Mike Kestner <mkestner@novell.com>

* 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]

svn path=/trunk/gtk-sharp/; revision=40007
This commit is contained in:
Mike Kestner 2005-02-02 21:57:15 +00:00
parent a8f16beaa7
commit 6590388024
9 changed files with 362 additions and 335 deletions

View file

@ -1,3 +1,19 @@
2005-02-02 Mike Kestner <mkestner@novell.com>
* 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 <jymdman@home.se>
* glib/Marshaller.cs : DateTime marshaling fix.

View file

@ -39,7 +39,6 @@ sources = \
Property.cs \
ReturnValue.cs \
Signal.cs \
SignalHandler.cs \
Signature.cs \
SimpleBase.cs \
SimpleGen.cs \

View file

@ -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();

View file

@ -1,211 +0,0 @@
// GtkSharp.Generation.SignalHandler.cs - The SignalHandler marshaling Class.
//
// Author: Mike Kestner <mkestner@ximian.com>
//
// 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();
}
}
}

View file

@ -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);
}
}
}

View file

@ -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 \

View file

@ -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)

193
glib/Signal.cs Normal file
View file

@ -0,0 +1,193 @@
// GLib.Signal.cs - signal marshaling class
//
// Authors: Mike Kestner <mkestner@novell.com>
//
// 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);
}
}

View file

@ -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.