From c93ecb7f887cf036aeb9e870cf92df3de8a3d05f Mon Sep 17 00:00:00 2001 From: Mike Kestner Date: Tue, 11 Sep 2007 20:34:24 +0000 Subject: [PATCH] 2007-09-11 Mike Kestner * gtk/Gtk.metadata: virtual_method rules for GInterface generation. * generator/ReturnValue.cs (ToNative): new method for the virtual method generation. * generator/Parameters.cs (FromNative): null guarding. * generator/ManagedCallString.cs: rework for interface method generation including callback and error param support. * generator/CallbackGen.cs: Invoker support. new class that deals with persistence of native and wrapper delegates in native to managed callback method signatures. * generator/VirtualMethod.cs: support for generation of interface methods, and all the funky parameters that come with that. * generator/InterfaceGen.cs: Fill out the adapter implementation. * generator/MethodBody.cs: Initialize overload. Extend ThrowsException to support GError outside the last parameter slot. * glib/GInterfaceAttribute.cs: New attribute to mark interfaces and obtain adapter type. * glib/Object.cs (AddInterfaces): interface registration method. * glib/GInterfaceAdapter.cs: New abstract class for interface adapter generation. * glib/Makefile.am: add new files. svn path=/trunk/gtk-sharp/; revision=85658 --- ChangeLog | 23 ++++++++++ generator/CallbackGen.cs | 81 ++++++++++++++++++++++++++++++++- generator/InterfaceGen.cs | 83 ++++++++++++++++++++++------------ generator/ManagedCallString.cs | 40 ++++++++++++---- generator/MethodBody.cs | 19 ++++++-- generator/Parameters.cs | 4 +- generator/ReturnValue.cs | 16 +++++++ generator/VirtualMethod.cs | 73 ++++++++++++++++++++++++------ glib/GInterfaceAdapter.cs | 67 +++++++++++++++++++++++++++ glib/GInterfaceAttribute.cs | 42 +++++++++++++++++ glib/Makefile.am | 2 + glib/Object.cs | 19 ++++++++ gtk/Gtk.metadata | 35 ++++++++++---- 13 files changed, 435 insertions(+), 69 deletions(-) create mode 100644 glib/GInterfaceAdapter.cs create mode 100644 glib/GInterfaceAttribute.cs diff --git a/ChangeLog b/ChangeLog index a3b2b27ec..c62f64e30 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2007-09-11 Mike Kestner + + * gtk/Gtk.metadata: virtual_method rules for GInterface generation. + * generator/ReturnValue.cs (ToNative): new method for the virtual + method generation. + * generator/Parameters.cs (FromNative): null guarding. + * generator/ManagedCallString.cs: rework for interface method + generation including callback and error param support. + * generator/CallbackGen.cs: Invoker support. new class that deals + with persistence of native and wrapper delegates in native to managed + callback method signatures. + * generator/VirtualMethod.cs: support for generation of interface + methods, and all the funky parameters that come with that. + * generator/InterfaceGen.cs: Fill out the adapter implementation. + * generator/MethodBody.cs: Initialize overload. Extend ThrowsException + to support GError outside the last parameter slot. + * glib/GInterfaceAttribute.cs: New attribute to mark interfaces and + obtain adapter type. + * glib/Object.cs (AddInterfaces): interface registration method. + * glib/GInterfaceAdapter.cs: New abstract class for interface + adapter generation. + * glib/Makefile.am: add new files. + 2007-09-11 Mike Kestner * gtk/Object.custom (Destroy): add a null check to avoid diff --git a/generator/CallbackGen.cs b/generator/CallbackGen.cs index ad1e41c34..70ccbf624 100644 --- a/generator/CallbackGen.cs +++ b/generator/CallbackGen.cs @@ -60,6 +60,14 @@ namespace GtkSharp.Generation { return true; } + public string InvokerName { + get { + if (!valid) + return String.Empty; + return NS + "Sharp." + Name + "Invoker"; + } + } + public override string MarshalType { get { if (valid) @@ -86,6 +94,72 @@ namespace GtkSharp.Generation { sw.WriteLine (indent + "}"); } + string CastFromInt (string type) + { + return type != "int" ? "(" + type + ") " : ""; + } + + string InvokeString { + get { + if (parms.Count == 0) + return String.Empty; + + string[] result = new string [parms.Count]; + for (int i = 0; i < parms.Count; i++) { + Parameter p = parms [i]; + IGeneratable igen = p.Generatable; + + if (i > 0 && parms [i - 1].IsString && p.IsLength) { + string string_name = parms [i - 1].Name; + result[i] = igen.CallByName (CastFromInt (p.CSType) + "System.Text.Encoding.UTF8.GetByteCount (" + string_name + ")"); + continue; + } + + p.CallName = p.Name; + result [i] = p.CallString; + if (p.IsUserData) + result [i] = "IntPtr.Zero"; + } + + return String.Join (", ", result); + } + } + + MethodBody body; + + void GenInvoker (GenerationInfo gen_info, StreamWriter sw) + { + sw.WriteLine ("\tinternal class " + Name + "Invoker {"); + sw.WriteLine (); + sw.WriteLine ("\t\t" + Name + "Native native_cb;"); + sw.WriteLine (); + sw.WriteLine ("\t\tinternal " + Name + "Invoker (" + Name + "Native native_cb)"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tthis.native_cb = native_cb;"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + sw.WriteLine ("\t\tinternal " + QualifiedName + " Handler {"); + sw.WriteLine ("\t\t\tget {"); + sw.WriteLine ("\t\t\t\treturn new " + QualifiedName + "(InvokeNative);"); + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + sw.WriteLine ("\t\t" + retval.CSType + " InvokeNative (" + sig + ")"); + sw.WriteLine ("\t\t{"); + body.Initialize (gen_info); + string call = "native_cb (" + InvokeString + ")"; + if (retval.IsVoid) + sw.WriteLine ("\t\t\t" + call + ";"); + else + sw.WriteLine ("\t\t\t" + retval.CSType + " result = " + retval.FromNative (call) + ";"); + body.Finish (sw, String.Empty); + if (!retval.IsVoid) + sw.WriteLine ("\t\t\treturn result;"); + sw.WriteLine ("\t\t}"); + sw.WriteLine ("\t}"); + sw.WriteLine (); + } + public string GenWrapper (GenerationInfo gen_info) { string wrapper = Name + "Native"; @@ -94,7 +168,10 @@ namespace GtkSharp.Generation { if (!Validate ()) return String.Empty; - StreamWriter sw = gen_info.OpenStream (qualname); + body = new MethodBody (parms); + + StreamWriter save_sw = gen_info.Writer; + StreamWriter sw = gen_info.Writer = gen_info.OpenStream (qualname); sw.WriteLine ("namespace " + NS + "Sharp {"); sw.WriteLine (); @@ -105,6 +182,7 @@ namespace GtkSharp.Generation { sw.WriteLine ("\t[GLib.CDeclCallback]"); sw.WriteLine ("\tinternal delegate " + retval.MarshalType + " " + wrapper + "(" + parms.ImportSignature + ");"); sw.WriteLine (); + GenInvoker (gen_info, sw); sw.WriteLine ("\tinternal class " + Name + "Wrapper {"); sw.WriteLine (); sw.WriteLine ("\t\tpublic " + retval.MarshalType + " NativeCallback (" + parms.ImportSignature + ")"); @@ -214,6 +292,7 @@ namespace GtkSharp.Generation { sw.WriteLine ("#endregion"); sw.WriteLine ("}"); sw.Close (); + gen_info.Writer = save_sw; return NS + "Sharp." + Name + "Wrapper"; } diff --git a/generator/InterfaceGen.cs b/generator/InterfaceGen.cs index b080361c1..abea6e7e7 100644 --- a/generator/InterfaceGen.cs +++ b/generator/InterfaceGen.cs @@ -81,14 +81,15 @@ namespace GtkSharp.Generation { return; foreach (VirtualMethod vm in vms) { - sw.WriteLine ("\t\t" + vm.NativeDelegate); + if (vm.IsValid) + sw.WriteLine ("\t\t" + vm.NativeDelegate); } sw.WriteLine (); } void GenerateIfaceStruct (StreamWriter sw) { - sw.WriteLine ("\t\t" + IfaceName + " iface;"); + sw.WriteLine ("\t\tstatic " + IfaceName + " iface;"); sw.WriteLine (); sw.WriteLine ("\t\tstruct " + IfaceName + " {"); sw.WriteLine ("\t\t\tpublic IntPtr gtype;"); @@ -100,7 +101,11 @@ namespace GtkSharp.Generation { sw.WriteLine ("\t\t\tpublic IntPtr " + member + ";"); else if (member is VirtualMethod) { VirtualMethod vm = member as VirtualMethod; - sw.WriteLine ("\t\t\tpublic " + vm.Name + "Delegate " + vm.CName + ";"); + bool has_method = methods [vm.Name] != null; + if (!has_method) + Console.WriteLine ("Interface " + QualifiedName + " virtual method " + vm.Name + " has no matching method to invoke."); + string type = has_method && vm.IsValid ? vm.Name + "Delegate" : "IntPtr"; + sw.WriteLine ("\t\t\tpublic " + type + " " + vm.CName + ";"); } } @@ -108,49 +113,64 @@ namespace GtkSharp.Generation { sw.WriteLine (); } - void GenerateCtor (StreamWriter sw) + void GenerateStaticCtor (StreamWriter sw) { - sw.WriteLine ("\t\tprivate " + Name + "Adapter ()"); + sw.WriteLine ("\t\tstatic " + Name + "Adapter ()"); sw.WriteLine ("\t\t{"); - foreach (VirtualMethod vm in vms) - sw.WriteLine ("\t\t\tiface.{0} = new {1}Delegate ({1}Callback);", vm.CName, vm.Name); - sw.WriteLine ("\t\t}"); - sw.WriteLine (); - } - - void GenerateAdapterProp (StreamWriter sw) - { - sw.WriteLine ("\t\tstatic " + Name + "Adapter singleton;"); - sw.WriteLine (); - sw.WriteLine ("\t\tinternal " + Name + "Adapter Adapter {"); - sw.WriteLine ("\t\t\tget {"); - sw.WriteLine ("\t\t\t\tif (singleton == null)"); - sw.WriteLine ("\t\t\t\t\tsingleton = new " + Name + "Adapter ();"); - sw.WriteLine ("\t\t\t\treturn singleton;"); - sw.WriteLine ("\t\t\t}"); + foreach (VirtualMethod vm in vms) { + bool has_method = methods [vm.Name] != null; + if (has_method && vm.IsValid) + sw.WriteLine ("\t\t\tiface.{0} = new {1}Delegate ({1}Callback);", vm.CName, vm.Name); + } sw.WriteLine ("\t\t}"); sw.WriteLine (); } void GenerateInitialize (StreamWriter sw) { - sw.WriteLine ("\t\tpublic void Initialize (IntPtr ifaceptr, IntPtr data)"); + sw.WriteLine ("\t\tstatic void Initialize (IntPtr ifaceptr, IntPtr data)"); sw.WriteLine ("\t\t{"); - sw.WriteLine ("\t\t\t" + IfaceName + " iface = (" + IfaceName + ") Marshal.PtrToStructure (ifaceptr, typeof (" + IfaceName + "));"); + sw.WriteLine ("\t\t\t" + IfaceName + " native_iface = (" + IfaceName + ") Marshal.PtrToStructure (ifaceptr, typeof (" + IfaceName + "));"); foreach (VirtualMethod vm in vms) - sw.WriteLine ("\t\t\tiface." + vm.CName + " = this.iface." + vm.CName + ";"); - sw.WriteLine ("\t\t\tMarshal.StructureToPtr (iface, ifaceptr, false);"); + sw.WriteLine ("\t\t\tnative_iface." + vm.CName + " = iface." + vm.CName + ";"); + sw.WriteLine ("\t\t\tMarshal.StructureToPtr (native_iface, ifaceptr, false);"); + sw.WriteLine ("\t\t\tGCHandle gch = (GCHandle) data;"); + sw.WriteLine ("\t\t\tgch.Free ();"); sw.WriteLine ("\t\t}"); + sw.WriteLine (); } void GenerateCallbacks (StreamWriter sw) { foreach (VirtualMethod vm in vms) { + if (methods [vm.Name] == null) + continue; sw.WriteLine (); vm.GenerateCallback (sw); } } + void GenerateCtor (StreamWriter sw) + { + sw.WriteLine ("\t\tpublic " + Name + "Adapter ()"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tInitHandler = new GLib.GInterfaceInitHandler (Initialize);"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + void GenerateGType (StreamWriter sw) + { + Method m = GetMethod ("GetType"); + m.GenerateImport (sw); + sw.WriteLine ("\t\tpublic override GLib.GType GType {"); + sw.WriteLine ("\t\t\tget {"); + sw.WriteLine ("\t\t\t\treturn new GLib.GType (" + m.CName + " ());"); + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + void GenerateAdapter (GenerationInfo gen_info) { StreamWriter sw = gen_info.Writer = gen_info.OpenStream (Name + "Adapter"); @@ -166,10 +186,11 @@ namespace GtkSharp.Generation { GenerateDelegates (sw); GenerateIfaceStruct (sw); - GenerateCtor (sw); - GenerateAdapterProp (sw); - GenerateInitialize (sw); + GenerateStaticCtor (sw); GenerateCallbacks (sw); + GenerateInitialize (sw); + GenerateCtor (sw); + GenerateGType (sw); sw.WriteLine ("\t}"); sw.WriteLine ("#endregion"); @@ -253,11 +274,12 @@ namespace GtkSharp.Generation { Statistics.IFaceCount++; } +#if false public void GenerateNotQuiteReadyYet (GenerationInfo gen_info) { ArrayList tmp = new ArrayList (); foreach (VirtualMethod vm in vms) { - if (vm.Validate()) + if (vm.IsValid) tmp.Add (vm); else { members.Remove (vm); @@ -268,9 +290,11 @@ namespace GtkSharp.Generation { GenerateAdapter (gen_info); GenerateInterface (gen_info); } +#endif public override void Generate (GenerationInfo gen_info) { + GenerateAdapter (gen_info); StreamWriter sw = gen_info.Writer = gen_info.OpenStream (Name); sw.WriteLine ("namespace " + NS + " {"); @@ -278,6 +302,7 @@ namespace GtkSharp.Generation { sw.WriteLine ("\tusing System;"); sw.WriteLine (); sw.WriteLine ("#region Autogenerated code"); + sw.WriteLine ("\t[GLib.GInterface (typeof (" + Name + "Adapter))]"); sw.WriteLine ("\tpublic interface " + Name + " : GLib.IWrapper {"); sw.WriteLine (); diff --git a/generator/ManagedCallString.cs b/generator/ManagedCallString.cs index dfecc4da5..2405d8b1b 100644 --- a/generator/ManagedCallString.cs +++ b/generator/ManagedCallString.cs @@ -29,18 +29,26 @@ namespace GtkSharp.Generation { ArrayList parms = new ArrayList (); ArrayList special = new ArrayList (); + bool has_error; public ManagedCallString (Parameters parms) { for (int i = 1; i < parms.Count; i ++) { Parameter p = parms [i]; - if (p.IsLength && parms [i-1].IsString) + if (p.IsLength && parms [i-1].IsString) continue; + else if (p.Scope == "notified") + i += 2; + + else if (p is ErrorParameter) { + has_error = true; + continue; + } this.parms.Add (p); - IGeneratable igen = p.Generatable; - if ((igen is StructGen || p.PassAs != "") && - (p.Name != p.FromNative (p.Name))) + if (p.PassAs != String.Empty && (p.Name != p.FromNative (p.Name))) + this.special.Add (true); + else if (p.Generatable is CallbackGen) this.special.Add (true); else this.special.Add (false); @@ -51,6 +59,9 @@ namespace GtkSharp.Generation { { string ret = ""; + if (has_error) + ret = indent + "error = IntPtr.Zero;\n"; + for (int i = 0; i < parms.Count; i ++) { if ((bool)special[i] == false) continue; @@ -58,10 +69,14 @@ namespace GtkSharp.Generation { Parameter p = parms [i] as Parameter; IGeneratable igen = p.Generatable; - ret += indent + igen.QualifiedName + " my" + p.Name; - if (igen is StructGen || p.PassAs == "ref") - ret += " = " + p.FromNative (p.Name); - ret += ";\n"; + if (igen is CallbackGen) { + ret += indent + String.Format ("{0} {1}_invoker = new {0} ({1});\n", (igen as CallbackGen).InvokerName, p.Name); + } else { + ret += indent + igen.QualifiedName + " my" + p.Name; + if (p.PassAs == "ref") + ret += " = " + p.FromNative (p.Name); + ret += ";\n"; + } } return ret; @@ -77,7 +92,10 @@ namespace GtkSharp.Generation { for (int i = 0; i < parms.Count; i ++) { Parameter p = parms [i] as Parameter; result [i] = p.PassAs == "" ? "" : p.PassAs + " "; - result [i] += ((bool)special[i]) ? "my" + p.Name : p.FromNative (p.Name); + if (p.Generatable is CallbackGen) + result [i] += p.Name + "_invoker.Handler"; + else + result [i] += ((bool)special[i]) ? "my" + p.Name : p.FromNative (p.Name); } return String.Join (", ", result); @@ -94,7 +112,9 @@ namespace GtkSharp.Generation { Parameter p = parms [i] as Parameter; IGeneratable igen = p.Generatable; - if (igen is StructBase) + if (igen is CallbackGen) + continue; + else if (igen is StructBase || igen is ByRefGen) ret += indent + String.Format ("if ({0} != IntPtr.Zero) System.Runtime.InteropServices.Marshal.StructureToPtr (my{0}, {0}, false);\n", p.Name); else ret += indent + p.Name + " = " + igen.ToNativeReturn ("my" + p.Name) + ";\n"; diff --git a/generator/MethodBody.cs b/generator/MethodBody.cs index 9f654a8ac..68d969162 100644 --- a/generator/MethodBody.cs +++ b/generator/MethodBody.cs @@ -75,6 +75,11 @@ namespace GtkSharp.Generation { return String.Join (", ", result); } + public void Initialize (GenerationInfo gen_info) + { + Initialize (gen_info, false, false, String.Empty); + } + public void Initialize (GenerationInfo gen_info, bool is_get, bool is_set, string indent) { if (parameters.Count == 0) @@ -124,7 +129,6 @@ namespace GtkSharp.Generation { sw.WriteLine (indent + "\t\t\t{0} {1}_wrapper = new {0} ({1});", wrapper, name); break; } - } } @@ -158,10 +162,17 @@ namespace GtkSharp.Generation { public bool ThrowsException { get { - if (parameters.Count < 1) - return false; + int idx = parameters.Count - 1; - return parameters [parameters.Count - 1].CType == "GError**"; + while (idx >= 0) { + if (parameters [idx].IsUserData) + idx--; + else if (parameters [idx].CType == "GError**") + return true; + else + break; + } + return false; } } } diff --git a/generator/Parameters.cs b/generator/Parameters.cs index f6ed4c698..cc9c64c31 100644 --- a/generator/Parameters.cs +++ b/generator/Parameters.cs @@ -285,7 +285,9 @@ namespace GtkSharp.Generation { public string FromNative (string var) { - if (Generatable is HandleBase) + if (Generatable == null) + return String.Empty; + else if (Generatable is HandleBase) return ((HandleBase)Generatable).FromNative (var, Owned); else return Generatable.FromNative (var); diff --git a/generator/ReturnValue.cs b/generator/ReturnValue.cs index 37d971683..0d0fa3a22 100644 --- a/generator/ReturnValue.cs +++ b/generator/ReturnValue.cs @@ -137,6 +137,22 @@ namespace GtkSharp.Generation { return IGen.FromNativeReturn (var); } + public string ToNative (string var) + { + if (IGen == null) + return String.Empty; + + if (ElementType.Length > 0) { + string args = ", typeof (" + ElementType + "), " + (Owned ? "true" : "false") + ", " + (ElementsOwned ? "true" : "false"); + var = "new " + IGen.QualifiedName + "(" + var + args + ")"; + } + + if (IGen is IManualMarshaler) + return (IGen as IManualMarshaler).AllocNative (var); + else + return IGen.ToNativeReturn (var); + } + public bool Validate () { if (MarshalType == "" || CSType == "") { diff --git a/generator/VirtualMethod.cs b/generator/VirtualMethod.cs index ee9ad6f32..a167300d0 100644 --- a/generator/VirtualMethod.cs +++ b/generator/VirtualMethod.cs @@ -53,6 +53,24 @@ namespace GtkSharp.Generation { } } + bool IsGetter { + get { + return (Name.StartsWith ("Get") || Name.StartsWith ("Has")) && ((!retval.IsVoid && parms.Count == 1) || (retval.IsVoid && parms.Count == 2 && parms [1].PassAs == "out")); + } + } + + bool IsSetter { + get { + if (!Name.StartsWith ("Set") || !retval.IsVoid) + return false; + + if (parms.Count == 2 || (parms.Count == 4 && parms [1].Scope == "notified")) + return true; + else + return false; + } + } + public string MarshalReturnType { get { return SymbolTable.Table.GetToNativeReturnType (elem["return-type"].GetAttribute("type")); @@ -73,39 +91,64 @@ namespace GtkSharp.Generation { public void GenerateCallback (StreamWriter sw) { + if (!Validate ()) + return; + ManagedCallString call = new ManagedCallString (parms); string type = parms [0].CSType; string name = parms [0].Name; string call_string = "__obj." + Name + " (" + call + ")"; + if (IsGetter) + call_string = "__obj." + (Name.StartsWith ("Get") ? Name.Substring (3) : Name); + else if (IsSetter) + call_string = "__obj." + Name.Substring (3) + " = " + call; sw.WriteLine ("\t\tstatic " + MarshalReturnType + " " + Name + "Callback (" + parms.ImportSignature + ")"); sw.WriteLine ("\t\t{"); sw.WriteLine ("\t\t\t" + type + " __obj = GLib.Object.GetObject (" + name + ", false) as " + type + ";"); sw.Write (call.Setup ("\t\t\t")); - if (retval.CSType == "void") - sw.WriteLine ("\t\t\t" + call_string + ";"); - else { - sw.WriteLine ("\t\t\treturn " + SymbolTable.Table.ToNativeReturn (retval.CType, call_string) + ";"); - } + if (retval.IsVoid) { + if (IsGetter) { + Parameter p = parms [1]; + string out_name = p.Name; + if (p.MarshalType != p.CSType) + out_name = "my" + out_name; + sw.WriteLine ("\t\t\t" + out_name + " = " + call_string + ";"); + } else + sw.WriteLine ("\t\t\t" + call_string + ";"); + } else + sw.WriteLine ("\t\t\t" + retval.ToNativeType + " result = " + retval.ToNative (call_string) + ";"); sw.Write (call.Finish ("\t\t\t")); + if (!retval.IsVoid) + sw.WriteLine ("\t\t\treturn result;"); sw.WriteLine ("\t\t}"); } - public bool Validate () + enum ValidState { + Unvalidated, + Invalid, + Valid + } + + ValidState vstate = ValidState.Unvalidated; + + public bool IsValid { + get { + if (vstate == ValidState.Unvalidated) + return Validate (); + else + return vstate == ValidState.Valid; + } + } + + bool Validate () { if (!parms.Validate () || !retval.Validate ()) { Console.Write ("in virtual method " + Name + " "); + vstate = ValidState.Invalid; return false; } - for (int i = 0; i < parms.Count; i++) { - Parameter p = parms [i]; - if (p.Generatable is CallbackGen) { - Console.Write("Callback: " + p.CSType + " in virtual method " + Name + " "); - Statistics.ThrottledCount++; - return false; - } - } - + vstate = ValidState.Valid; return true; } } diff --git a/glib/GInterfaceAdapter.cs b/glib/GInterfaceAdapter.cs new file mode 100644 index 000000000..91b79b3b5 --- /dev/null +++ b/glib/GInterfaceAdapter.cs @@ -0,0 +1,67 @@ +// GInterfaceAdapter.cs +// +// Author: Mike Kestner +// +// Copyright (c) 2007 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; + + public delegate void GInterfaceInitHandler (IntPtr iface_ptr, IntPtr data); + + internal delegate void GInterfaceFinalizeHandler (IntPtr iface_ptr, IntPtr data); + + internal struct GInterfaceInfo { + internal GInterfaceInitHandler InitHandler; + internal GInterfaceFinalizeHandler FinalizeHandler; + internal IntPtr Data; + } + + public abstract class GInterfaceAdapter { + + GInterfaceInfo info; + + protected GInterfaceAdapter () + { + info.FinalizeHandler = new GInterfaceFinalizeHandler (Finalize); + info.Data = (IntPtr) GCHandle.Alloc (this); + } + + protected GInterfaceInitHandler InitHandler { + set { + info.InitHandler = value; + } + } + + public abstract GType GType { get; } + + internal GInterfaceInfo Info { + get { + return info; + } + } + + void Finalize (IntPtr iface_ptr, IntPtr data) + { + GCHandle gch = (GCHandle) data; + gch.Free (); + } + } +} diff --git a/glib/GInterfaceAttribute.cs b/glib/GInterfaceAttribute.cs new file mode 100644 index 000000000..58a55d10e --- /dev/null +++ b/glib/GInterfaceAttribute.cs @@ -0,0 +1,42 @@ +// GInterfaceAttribute.cs +// +// Copyright (c) 2007 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; + + [AttributeUsage (AttributeTargets.Interface)] + public sealed class GInterfaceAttribute : Attribute { + Type adapter_type; + + public GInterfaceAttribute (Type adapter_type) + { + this.adapter_type = adapter_type; + } + + public Type AdapterType { + get { + return adapter_type; + } + set { + adapter_type = value; + } + } + } +} diff --git a/glib/Makefile.am b/glib/Makefile.am index 58087ecbe..d0d1e25fa 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -28,6 +28,8 @@ sources = \ ExceptionManager.cs \ FileUtils.cs \ GException.cs \ + GInterfaceAdapter.cs \ + GInterfaceAttribute.cs \ GString.cs \ GType.cs \ GTypeAttribute.cs \ diff --git a/glib/Object.cs b/glib/Object.cs index 6e6cbff49..ac71fca48 100644 --- a/glib/Object.cs +++ b/glib/Object.cs @@ -183,6 +183,24 @@ namespace GLib { } } + [DllImport("libgobject-2.0-0.dll")] + static extern void g_type_add_interface_static (IntPtr gtype, IntPtr iface_type, ref GInterfaceInfo info); + + static void AddInterfaces (GType gtype, Type t) + { + foreach (Type iface in t.GetInterfaces ()) { + if (!iface.IsDefined (typeof (GInterfaceAttribute), true) || iface.IsAssignableFrom (t.BaseType)) + continue; + + GInterfaceAttribute attr = iface.GetCustomAttributes (typeof (GInterfaceAttribute), false) [0] as GInterfaceAttribute; + GInterfaceAdapter adapter = Activator.CreateInstance (attr.AdapterType, null) as GInterfaceAdapter; + + GInterfaceInfo info = adapter.Info; + g_type_add_interface_static (gtype.Val, adapter.GType.Val, ref info); + Console.WriteLine (adapter); + } + } + [DllImport("glibsharpglue-2")] static extern IntPtr gtksharp_register_type (IntPtr name, IntPtr parent_type); @@ -221,6 +239,7 @@ namespace GLib { GLib.GType.Register (gtype, t); ConnectDefaultHandlers (gtype, t); InvokeClassInitializers (gtype, t); + AddInterfaces (gtype, t); g_types[t] = gtype; return gtype; } diff --git a/gtk/Gtk.metadata b/gtk/Gtk.metadata index 3aadbb5c3..fbf53ca57 100644 --- a/gtk/Gtk.metadata +++ b/gtk/Gtk.metadata @@ -128,6 +128,10 @@ TextDeleted ref TextInserted + DeleteText + InsertText + ref + SelectRegion 1 gfilename* gfilename* @@ -146,17 +150,30 @@ gchar* true true + GetFilenames + gfilename* + true + true + GetFilters + gchar* + true + true + GetShortcutFolders + gchar* + true + true + 1 call - out + out 1 - out - out - true - ref - out - ref - out - out + out + out + true + ref + out + ref + out + out EmitRowChanged EmitRowDeleted EmitRowHasChildToggled