From 4582abb4f3abacc24e071c22a93357c2b8566a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 14 May 2009 21:38:28 +0200 Subject: [PATCH] Fork the Gtk# codegenerator for now We unfortunately need to do this to properly generate bindings for GstMiniObject... --- README | 4 - configure.ac | 15 +- doc/en/Gst.Interfaces/MixerMessage.xml | 42 +- generator/AliasGen.cs | 30 + generator/BoxedGen.cs | 84 +++ generator/ByRefGen.cs | 63 +++ generator/CallbackGen.cs | 306 ++++++++++ generator/ChildProperty.cs | 45 ++ generator/ClassBase.cs | 396 +++++++++++++ generator/ClassField.cs | 43 ++ generator/ClassGen.cs | 94 ++++ generator/CodeGenerator.cs | 122 ++++ generator/ConstFilenameGen.cs | 52 ++ generator/ConstStringGen.cs | 59 ++ generator/Ctor.cs | 168 ++++++ generator/DefaultSignalHandler.cs | 146 +++++ generator/EnumGen.cs | 132 +++++ generator/FieldBase.cs | 271 +++++++++ generator/GObjectVM.cs | 368 ++++++++++++ generator/GenBase.cs | 149 +++++ generator/GenerationInfo.cs | 176 ++++++ generator/HandleBase.cs | 81 +++ generator/IAccessor.cs | 29 + generator/IGeneratable.cs | 71 +++ generator/IManualMarshaler.cs | 32 ++ generator/InterfaceGen.cs | 351 ++++++++++++ generator/InterfaceVM.cs | 97 ++++ generator/LPGen.cs | 58 ++ generator/LPUGen.cs | 58 ++ generator/Makefile.am | 67 +++ generator/ManagedCallString.cs | 152 +++++ generator/ManualGen.cs | 58 ++ generator/MarshalGen.cs | 58 ++ generator/Method.cs | 304 ++++++++++ generator/MethodBase.cs | 183 ++++++ generator/MethodBody.cs | 177 ++++++ generator/ObjectBase.cs | 315 +++++++++++ generator/ObjectField.cs | 48 ++ generator/ObjectGen.cs | 416 ++++++++++++++ generator/OpaqueGen.cs | 237 ++++++++ generator/Parameters.cs | 737 +++++++++++++++++++++++++ generator/Parser.cs | 185 +++++++ generator/Property.cs | 193 +++++++ generator/PropertyBase.cs | 116 ++++ generator/ReturnValue.cs | 168 ++++++ generator/Signal.cs | 327 +++++++++++ generator/Signature.cs | 123 +++++ generator/SimpleBase.cs | 121 ++++ generator/SimpleGen.cs | 31 ++ generator/Statistics.cs | 197 +++++++ generator/StructBase.cs | 230 ++++++++ generator/StructField.cs | 149 +++++ generator/StructGen.cs | 53 ++ generator/SymbolTable.cs | 413 ++++++++++++++ generator/VMSignature.cs | 91 +++ generator/VirtualMethod.cs | 156 ++++++ generator/gst-codegen.diff | 24 + gstreamer-sharp/Makefile.am | 4 +- 58 files changed, 8820 insertions(+), 55 deletions(-) create mode 100644 generator/AliasGen.cs create mode 100644 generator/BoxedGen.cs create mode 100644 generator/ByRefGen.cs create mode 100644 generator/CallbackGen.cs create mode 100644 generator/ChildProperty.cs create mode 100644 generator/ClassBase.cs create mode 100644 generator/ClassField.cs create mode 100644 generator/ClassGen.cs create mode 100644 generator/CodeGenerator.cs create mode 100644 generator/ConstFilenameGen.cs create mode 100644 generator/ConstStringGen.cs create mode 100644 generator/Ctor.cs create mode 100644 generator/DefaultSignalHandler.cs create mode 100644 generator/EnumGen.cs create mode 100644 generator/FieldBase.cs create mode 100644 generator/GObjectVM.cs create mode 100644 generator/GenBase.cs create mode 100644 generator/GenerationInfo.cs create mode 100644 generator/HandleBase.cs create mode 100644 generator/IAccessor.cs create mode 100644 generator/IGeneratable.cs create mode 100644 generator/IManualMarshaler.cs create mode 100644 generator/InterfaceGen.cs create mode 100644 generator/InterfaceVM.cs create mode 100644 generator/LPGen.cs create mode 100644 generator/LPUGen.cs create mode 100644 generator/Makefile.am create mode 100644 generator/ManagedCallString.cs create mode 100644 generator/ManualGen.cs create mode 100644 generator/MarshalGen.cs create mode 100644 generator/Method.cs create mode 100644 generator/MethodBase.cs create mode 100644 generator/MethodBody.cs create mode 100644 generator/ObjectBase.cs create mode 100644 generator/ObjectField.cs create mode 100644 generator/ObjectGen.cs create mode 100644 generator/OpaqueGen.cs create mode 100644 generator/Parameters.cs create mode 100644 generator/Parser.cs create mode 100644 generator/Property.cs create mode 100644 generator/PropertyBase.cs create mode 100644 generator/ReturnValue.cs create mode 100644 generator/Signal.cs create mode 100644 generator/Signature.cs create mode 100644 generator/SimpleBase.cs create mode 100644 generator/SimpleGen.cs create mode 100644 generator/Statistics.cs create mode 100644 generator/StructBase.cs create mode 100644 generator/StructField.cs create mode 100644 generator/StructGen.cs create mode 100644 generator/SymbolTable.cs create mode 100644 generator/VMSignature.cs create mode 100644 generator/VirtualMethod.cs create mode 100644 generator/gst-codegen.diff diff --git a/README b/README index 811b92a07b..6807a02093 100644 --- a/README +++ b/README @@ -1,11 +1,7 @@ To build this Gtk# from trunk is required and the following patches: -http://bugzilla.novell.com/show_bug.cgi?id=323372 http://bugzilla.novell.com/show_bug.cgi?id=497667 -http://bugzilla.novell.com/show_bug.cgi?id=503048 -http://bugzilla.novell.com/show_bug.cgi?id=503060 http://bugzilla.novell.com/show_bug.cgi?id=499900 -http://bugzilla.novell.com/show_bug.cgi?id=503467 If you're using Mono < 2.4 you also need to apply: http://bugzilla.novell.com/show_bug.cgi?id=477396 diff --git a/configure.ac b/configure.ac index 3a28701e58..8afcb9bc5e 100644 --- a/configure.ac +++ b/configure.ac @@ -122,16 +122,6 @@ AM_CONDITIONAL(ENABLE_MONODOC, test "x$enable_monodoc" = "xyes") ## Check for the gapi programs PKG_CHECK_MODULES(GAPI, gapi-2.0 >= $GLIBSHARP_REQUIRED_VERSION) -AC_PATH_PROG(GAPI_CODEGEN, gapi2-codegen, no) -if test "x$GAPI_CODEGEN" = "xno"; then - AC_MSG_ERROR([You need to install gtk-sharp-gapi]) -fi - -AC_PATH_PROG(GAPI_FIXUP, gapi2-fixup, no) -if test "x$GAPI_FIXUP" = "xno"; then - AC_MSG_ERROR([You need to install gtk-sharp-gapi]) -fi - AC_PATH_PROG(GAPI_PARSER, gapi2-parser, no) if test "x$GAPI_PARSER" = "xno"; then AC_MSG_ERROR([You need to install gtk-sharp-gapi]) @@ -144,9 +134,14 @@ if test "x$do_tests" = "xno"; then AC_MSG_WARN([Could not find mono-nunit: tests will not be available]) fi +AC_CHECK_SIZEOF(off_t) +OFF_T_FLAGS="-define:OFF_T_$ac_cv_sizeof_off_t" +AC_SUBST(OFF_T_FLAGS) + AC_OUTPUT([ source/Makefile parser/Makefile +generator/Makefile gstreamer-sharp/Makefile gstreamer-sharp/AssemblyInfo.cs gstreamer-sharp/gstreamer-sharp.dll.config diff --git a/doc/en/Gst.Interfaces/MixerMessage.xml b/doc/en/Gst.Interfaces/MixerMessage.xml index 4ba565f720..10e1b11b4d 100644 --- a/doc/en/Gst.Interfaces/MixerMessage.xml +++ b/doc/en/Gst.Interfaces/MixerMessage.xml @@ -18,7 +18,8 @@ - + + Method @@ -27,42 +28,6 @@ Gst.Interfaces.MixerMessageType To be added.To be added.To be added.To be added. - - - Method - - 0.9.5.99 - - System.Void - - To be added.To be added.To be added.To be added.To be added. - - - Method - - 0.9.5.99 - - System.Void - - To be added.To be added.To be added.To be added. - - - Method - - 0.9.5.99 - - System.Void - - To be added.To be added.To be added.To be added.To be added. - - - Method - - 0.9.5.99 - - System.Void - - To be added.To be added.To be added.To be added.To be added. Method @@ -72,6 +37,5 @@ System.Void To be added.To be added.To be added.To be added.To be added. - - + Method0.9.5.99System.VoidTo be added.To be added.To be added.To be added.To be added.Method0.9.5.99System.VoidTo be added.To be added.To be added.To be added.Method0.9.5.99System.VoidTo be added.To be added.To be added.To be added.To be added.Method0.9.5.99System.VoidTo be added.To be added.To be added.To be added.To be added. diff --git a/generator/AliasGen.cs b/generator/AliasGen.cs new file mode 100644 index 0000000000..19911d6b65 --- /dev/null +++ b/generator/AliasGen.cs @@ -0,0 +1,30 @@ +// GtkSharp.Generation.AliasGen.cs - The Alias type Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2003 Mike Kestner +// +// 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; + + public class AliasGen : SimpleBase { + + public AliasGen (string ctype, string type) : base (ctype, type, String.Empty) {} + } +} + diff --git a/generator/BoxedGen.cs b/generator/BoxedGen.cs new file mode 100644 index 0000000000..5ad6d87495 --- /dev/null +++ b/generator/BoxedGen.cs @@ -0,0 +1,84 @@ +// GtkSharp.Generation.BoxedGen.cs - The Boxed Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// Copyright (c) 2003-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 BoxedGen : StructBase { + + public BoxedGen (XmlElement ns, XmlElement elem) : base (ns, elem) {} + + public override void Generate (GenerationInfo gen_info) + { + Method copy = methods["Copy"] as Method; + Method free = methods["Free"] as Method; + methods.Remove ("Copy"); + methods.Remove ("Free"); + + gen_info.CurrentType = Name; + + StreamWriter sw = gen_info.Writer = gen_info.OpenStream (Name); + base.Generate (gen_info); + sw.WriteLine ("\t\tpublic static explicit operator GLib.Value (" + QualifiedName + " boxed)"); + sw.WriteLine ("\t\t{"); + + sw.WriteLine ("\t\t\tGLib.Value val = GLib.Value.Empty;"); + sw.WriteLine ("\t\t\tval.Init (" + QualifiedName + ".GType);"); + sw.WriteLine ("\t\t\tval.Val = boxed;"); + sw.WriteLine ("\t\t\treturn val;"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + sw.WriteLine ("\t\tpublic static explicit operator " + QualifiedName + " (GLib.Value val)"); + sw.WriteLine ("\t\t{"); + + sw.WriteLine ("\t\t\treturn (" + QualifiedName + ") val.Val;"); + sw.WriteLine ("\t\t}"); + + if (copy != null && copy.IsDeprecated) { + sw.WriteLine (); + sw.WriteLine ("\t\t[Obsolete(\"This is a no-op\")]"); + sw.WriteLine ("\t\tpublic " + QualifiedName + " Copy() {"); + sw.WriteLine ("\t\t\treturn this;"); + sw.WriteLine ("\t\t}"); + } + + if (free != null && free.IsDeprecated) { + sw.WriteLine (); + sw.WriteLine ("\t\t[Obsolete(\"This is a no-op\")]"); + sw.WriteLine ("\t\tpublic " + QualifiedName + " Free () {"); + sw.WriteLine ("\t\t\treturn this;"); + sw.WriteLine ("\t\t}"); + } + + sw.WriteLine ("#endregion"); + AppendCustom(sw, gen_info.CustomDir); + sw.WriteLine ("\t}"); + sw.WriteLine ("}"); + sw.Close (); + gen_info.Writer = null; + Statistics.BoxedCount++; + } + } +} + diff --git a/generator/ByRefGen.cs b/generator/ByRefGen.cs new file mode 100644 index 0000000000..7a2641eb8b --- /dev/null +++ b/generator/ByRefGen.cs @@ -0,0 +1,63 @@ +// GtkSharp.Generation.ByRefGen.cs - The ByRef type Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 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; + + public class ByRefGen : SimpleBase, IManualMarshaler { + + public ByRefGen (string ctype, string type) : base (ctype, type, type + ".Empty") {} + + public override string MarshalType { + get { + return "IntPtr"; + } + } + + public override string CallByName (string var_name) + { + return "native_" + var_name; + } + + public string AllocNative () + { + return "Marshal.AllocHGlobal (Marshal.SizeOf (typeof (" + QualifiedName + ")))"; + } + + public string AllocNative (string var_name) + { + return "GLib.Marshaller.StructureToPtrAlloc (" + var_name + ")"; + } + + public override string FromNative (string var_name) + { + return String.Format ("({0}) Marshal.PtrToStructure ({1}, typeof ({0}))", QualifiedName, var_name); + } + + public string ReleaseNative (string var_name) + { + return "Marshal.FreeHGlobal (" + var_name + ")"; + } + } +} + diff --git a/generator/CallbackGen.cs b/generator/CallbackGen.cs new file mode 100644 index 0000000000..eff4cffb1b --- /dev/null +++ b/generator/CallbackGen.cs @@ -0,0 +1,306 @@ +// GtkSharp.Generation.CallbackGen.cs - The Callback Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2002-2003 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 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 CallbackGen : GenBase, IAccessor { + + private Parameters parms; + private Signature sig = null; + private ReturnValue retval; + private bool valid = true; + + public CallbackGen (XmlElement ns, XmlElement elem) : base (ns, elem) + { + retval = new ReturnValue (elem ["return-type"]); + parms = new Parameters (elem ["parameters"]); + parms.HideData = true; + } + + public override string DefaultValue { + get { return "null"; } + } + + public override bool Validate () + { + if (!retval.Validate ()) { + Console.WriteLine ("rettype: " + retval.CType + " in callback " + CName); + Statistics.ThrottledCount++; + valid = false; + return false; + } + + if (!parms.Validate ()) { + Console.WriteLine (" in callback " + CName); + Statistics.ThrottledCount++; + valid = false; + return false; + } + + valid = true; + return true; + } + + public string InvokerName { + get { + if (!valid) + return String.Empty; + return NS + "Sharp." + Name + "Invoker"; + } + } + + public override string MarshalType { + get { + if (valid) + return NS + "Sharp." + Name + "Native"; + else + return ""; + } + } + + public override string CallByName (string var_name) + { + return var_name + ".NativeDelegate"; + } + + public override string FromNative (string var) + { + return NS + "Sharp." + Name + "Wrapper.GetManagedDelegate (" + var + ")"; + } + + public void WriteAccessors (StreamWriter sw, string indent, string var) + { + sw.WriteLine (indent + "get {"); + sw.WriteLine (indent + "\treturn " + FromNative (var) + ";"); + 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] = "__data"; + } + + return String.Join (", ", result); + } + } + + MethodBody body; + + void GenInvoker (GenerationInfo gen_info, StreamWriter sw) + { + if (sig == null) + sig = new Signature (parms); + + sw.WriteLine ("\tinternal class " + Name + "Invoker {"); + sw.WriteLine (); + sw.WriteLine ("\t\t" + Name + "Native native_cb;"); + sw.WriteLine ("\t\tIntPtr __data;"); + sw.WriteLine ("\t\tGLib.DestroyNotify __notify;"); + sw.WriteLine (); + sw.WriteLine ("\t\t~" + Name + "Invoker ()"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tif (__notify == null)"); + sw.WriteLine ("\t\t\t\treturn;"); + sw.WriteLine ("\t\t\t__notify (__data);"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + sw.WriteLine ("\t\tinternal " + Name + "Invoker (" + Name + "Native native_cb) : this (native_cb, IntPtr.Zero, null) {}"); + sw.WriteLine (); + sw.WriteLine ("\t\tinternal " + Name + "Invoker (" + Name + "Native native_cb, IntPtr data) : this (native_cb, data, null) {}"); + sw.WriteLine (); + sw.WriteLine ("\t\tinternal " + Name + "Invoker (" + Name + "Native native_cb, IntPtr data, GLib.DestroyNotify notify)"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tthis.native_cb = native_cb;"); + sw.WriteLine ("\t\t\t__data = data;"); + sw.WriteLine ("\t\t\t__notify = notify;"); + 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"; + string qualname = MarshalType; + + if (!Validate ()) + return String.Empty; + + 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 (); + sw.WriteLine ("\tusing System;"); + sw.WriteLine ("\tusing System.Runtime.InteropServices;"); + sw.WriteLine (); + sw.WriteLine ("#region Autogenerated code"); + 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 (); + ManagedCallString call = new ManagedCallString (parms); + sw.WriteLine ("\t\tpublic " + retval.MarshalType + " NativeCallback (" + parms.ImportSignature + ")"); + sw.WriteLine ("\t\t{"); + string unconditional = call.Unconditional ("\t\t\t"); + if (unconditional.Length > 0) + sw.WriteLine (unconditional); + sw.WriteLine ("\t\t\ttry {"); + string call_setup = call.Setup ("\t\t\t\t"); + if (call_setup.Length > 0) + sw.WriteLine (call_setup); + if (retval.CSType == "void") + sw.WriteLine ("\t\t\t\tmanaged ({0});", call); + else + sw.WriteLine ("\t\t\t\t{0} __ret = managed ({1});", retval.CSType, call); + string finish = call.Finish ("\t\t\t\t"); + if (finish.Length > 0) + sw.WriteLine (finish); + sw.WriteLine ("\t\t\t\tif (release_on_call)\n\t\t\t\t\tgch.Free ();"); + if (retval.CSType != "void") + sw.WriteLine ("\t\t\t\treturn {0};", retval.ToNative ("__ret")); + + /* If the function expects one or more "out" parameters(error parameters are excluded) or has a return value different from void and bool, exceptions + * thrown in the managed function have to be considered fatal meaning that an exception is to be thrown and the function call cannot not return + */ + bool fatal = (retval.MarshalType != "void" && retval.MarshalType != "bool") || call.HasOutParam; + sw.WriteLine ("\t\t\t} catch (Exception e) {"); + sw.WriteLine ("\t\t\t\tGLib.ExceptionManager.RaiseUnhandledException (e, " + (fatal ? "true" : "false") + ");"); + if (fatal) { + sw.WriteLine ("\t\t\t\t// NOTREACHED: Above call does not return."); + sw.WriteLine ("\t\t\t\tthrow e;"); + } else if (retval.MarshalType == "bool") { + sw.WriteLine ("\t\t\t\treturn false;"); + } + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + sw.WriteLine ("\t\tbool release_on_call = false;"); + sw.WriteLine ("\t\tGCHandle gch;"); + sw.WriteLine (); + sw.WriteLine ("\t\tpublic void PersistUntilCalled ()"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\trelease_on_call = true;"); + sw.WriteLine ("\t\t\tgch = GCHandle.Alloc (this);"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + sw.WriteLine ("\t\tinternal " + wrapper + " NativeDelegate;"); + sw.WriteLine ("\t\t" + NS + "." + Name + " managed;"); + sw.WriteLine (); + sw.WriteLine ("\t\tpublic " + Name + "Wrapper (" + NS + "." + Name + " managed)"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tthis.managed = managed;"); + sw.WriteLine ("\t\t\tif (managed != null)"); + sw.WriteLine ("\t\t\t\tNativeDelegate = new " + wrapper + " (NativeCallback);"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + sw.WriteLine ("\t\tpublic static " + NS + "." + Name + " GetManagedDelegate (" + wrapper + " native)"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tif (native == null)"); + sw.WriteLine ("\t\t\t\treturn null;"); + sw.WriteLine ("\t\t\t" + Name + "Wrapper wrapper = (" + Name + "Wrapper) native.Target;"); + sw.WriteLine ("\t\t\tif (wrapper == null)"); + sw.WriteLine ("\t\t\t\treturn null;"); + sw.WriteLine ("\t\t\treturn wrapper.managed;"); + sw.WriteLine ("\t\t}"); + sw.WriteLine ("\t}"); + sw.WriteLine ("#endregion"); + sw.WriteLine ("}"); + sw.Close (); + gen_info.Writer = save_sw; + return NS + "Sharp." + Name + "Wrapper"; + } + + public override void Generate (GenerationInfo gen_info) + { + gen_info.CurrentType = Name; + + sig = new Signature (parms); + + StreamWriter sw = gen_info.OpenStream (Name); + + sw.WriteLine ("namespace " + NS + " {"); + sw.WriteLine (); + sw.WriteLine ("\tusing System;"); + sw.WriteLine (); + sw.WriteLine ("\t{0} delegate " + retval.CSType + " " + Name + "(" + sig.ToString() + ");", IsInternal ? "internal" : "public"); + sw.WriteLine (); + sw.WriteLine ("}"); + + sw.Close (); + + GenWrapper (gen_info); + + Statistics.CBCount++; + } + } +} + diff --git a/generator/ChildProperty.cs b/generator/ChildProperty.cs new file mode 100644 index 0000000000..fe361edf14 --- /dev/null +++ b/generator/ChildProperty.cs @@ -0,0 +1,45 @@ +// GtkSharp.Generation.ChildProperty.cs - GtkContainer child properties +// +// 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.Collections; + using System.IO; + using System.Xml; + + public class ChildProperty : Property { + + public ChildProperty (XmlElement elem, ClassBase container_type) : base (elem, container_type) {} + + protected override string PropertyAttribute (string qpname) { + return "[Gtk.ChildProperty (" + qpname + ")]"; + } + + protected override string RawGetter (string qpname) { + return "parent.ChildGetProperty (child, " + qpname + ")"; + } + + protected override string RawSetter (string qpname) { + return "parent.ChildSetProperty(child, " + qpname + ", val)"; + } + + } +} + diff --git a/generator/ClassBase.cs b/generator/ClassBase.cs new file mode 100644 index 0000000000..407f58f443 --- /dev/null +++ b/generator/ClassBase.cs @@ -0,0 +1,396 @@ +// GtkSharp.Generation.ClassBase.cs - Common code between object +// and interface wrappers +// +// Authors: Rachel Hestilow +// Mike Kestner +// +// Copyright (c) 2002 Rachel Hestilow +// Copyright (c) 2001-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.Collections; + using System.IO; + using System.Xml; + + public abstract class ClassBase : GenBase { + protected Hashtable props = new Hashtable(); + protected Hashtable fields = new Hashtable(); + protected Hashtable methods = new Hashtable(); + protected ArrayList interfaces = new ArrayList(); + protected ArrayList managed_interfaces = new ArrayList(); + protected ArrayList ctors = new ArrayList(); + + private bool ctors_initted = false; + private Hashtable clash_map; + private bool deprecated = false; + private bool isabstract = false; + + public Hashtable Methods { + get { + return methods; + } + } + + public ClassBase Parent { + get { + string parent = Elem.GetAttribute("parent"); + + if (parent == "") + return null; + else + return SymbolTable.Table.GetClassGen(parent); + } + } + + protected ClassBase (XmlElement ns, XmlElement elem) : base (ns, elem) { + + if (elem.HasAttribute ("deprecated")) { + string attr = elem.GetAttribute ("deprecated"); + deprecated = attr == "1" || attr == "true"; + } + + if (elem.HasAttribute ("abstract")) { + string attr = elem.GetAttribute ("abstract"); + isabstract = attr == "1" || attr == "true"; + } + + foreach (XmlNode node in elem.ChildNodes) { + if (!(node is XmlElement)) continue; + XmlElement member = (XmlElement) node; + if (member.HasAttribute ("hidden")) + continue; + + string name; + switch (node.Name) { + case "method": + name = member.GetAttribute("name"); + while (methods.ContainsKey(name)) + name += "mangled"; + methods.Add (name, new Method (member, this)); + break; + + case "property": + name = member.GetAttribute("name"); + while (props.ContainsKey(name)) + name += "mangled"; + props.Add (name, new Property (member, this)); + break; + + case "field": + name = member.GetAttribute("name"); + while (fields.ContainsKey (name)) + name += "mangled"; + fields.Add (name, new ObjectField (member, this)); + break; + + case "implements": + ParseImplements (member); + break; + + case "constructor": + ctors.Add (new Ctor (member, this)); + break; + + default: + break; + } + } + } + + public override bool Validate () + { + foreach (string iface in interfaces) { + InterfaceGen igen = SymbolTable.Table[iface] as InterfaceGen; + if (igen == null) { + Console.WriteLine (QualifiedName + " implements unknown GInterface " + iface); + return false; + } + if (!igen.ValidateForSubclass ()) { + Console.WriteLine (QualifiedName + " implements invalid GInterface " + iface); + return false; + } + } + + ArrayList invalids = new ArrayList (); + + foreach (Property prop in props.Values) { + if (!prop.Validate ()) { + Console.WriteLine ("in type " + QualifiedName); + invalids.Add (prop); + } + } + foreach (Property prop in invalids) + props.Remove (prop.Name); + invalids.Clear (); + + foreach (ObjectField field in fields.Values) { + if (!field.Validate ()) { + Console.WriteLine ("in type " + QualifiedName); + invalids.Add (field); + } + } + foreach (ObjectField field in invalids) + fields.Remove (field.Name); + invalids.Clear (); + + foreach (Method method in methods.Values) { + if (!method.Validate ()) { + Console.WriteLine ("in type " + QualifiedName); + invalids.Add (method); + } + } + foreach (Method method in invalids) + methods.Remove (method.Name); + invalids.Clear (); + + foreach (Ctor ctor in ctors) { + if (!ctor.Validate ()) { + Console.WriteLine ("in type " + QualifiedName); + invalids.Add (ctor); + } + } + foreach (Ctor ctor in invalids) + ctors.Remove (ctor); + invalids.Clear (); + + return true; + } + + public bool IsDeprecated { + get { + return deprecated; + } + } + + public bool IsAbstract { + get { + return isabstract; + } + } + + public abstract string AssignToName { get; } + + public abstract string CallByName (); + + public override string DefaultValue { + get { + return "null"; + } + } + + protected virtual bool IsNodeNameHandled (string name) + { + switch (name) { + case "method": + case "property": + case "field": + case "signal": + case "implements": + case "constructor": + case "disabledefaultconstructor": + return true; + + default: + return false; + } + } + + public void GenProperties (GenerationInfo gen_info, ClassBase implementor) + { + if (props.Count == 0) + return; + + foreach (Property prop in props.Values) + prop.Generate (gen_info, "\t\t", implementor); + } + + protected void GenFields (GenerationInfo gen_info) + { + foreach (ObjectField field in fields.Values) + field.Generate (gen_info, "\t\t"); + } + + private void ParseImplements (XmlElement member) + { + foreach (XmlNode node in member.ChildNodes) { + if (node.Name != "interface") + continue; + XmlElement element = (XmlElement) node; + if (element.HasAttribute ("hidden")) + continue; + if (element.HasAttribute ("cname")) + interfaces.Add (element.GetAttribute ("cname")); + else if (element.HasAttribute ("name")) + managed_interfaces.Add (element.GetAttribute ("name")); + } + } + + protected bool IgnoreMethod (Method method, ClassBase implementor) + { + if (implementor != null && implementor.QualifiedName != this.QualifiedName && method.IsStatic) + return true; + + string mname = method.Name; + return ((method.IsSetter || (method.IsGetter && mname.StartsWith("Get"))) && + ((props != null) && props.ContainsKey(mname.Substring(3)) || + (fields != null) && fields.ContainsKey(mname.Substring(3)))); + } + + public void GenMethods (GenerationInfo gen_info, Hashtable collisions, ClassBase implementor) + { + if (methods == null) + return; + + foreach (Method method in methods.Values) { + if (IgnoreMethod (method, implementor)) + continue; + + string oname = null, oprotection = null; + if (collisions != null && collisions.Contains (method.Name)) { + oname = method.Name; + oprotection = method.Protection; + method.Name = QualifiedName + "." + method.Name; + method.Protection = ""; + } + method.Generate (gen_info, implementor); + if (oname != null) { + method.Name = oname; + method.Protection = oprotection; + } + } + } + + public Method GetMethod (string name) + { + return (Method) methods[name]; + } + + public Property GetProperty (string name) + { + return (Property) props[name]; + } + + public Method GetMethodRecursively (string name) + { + return GetMethodRecursively (name, false); + } + + public virtual Method GetMethodRecursively (string name, bool check_self) + { + Method p = null; + if (check_self) + p = GetMethod (name); + if (p == null && Parent != null) + p = Parent.GetMethodRecursively (name, true); + + if (check_self && p == null) { + foreach (string iface in interfaces) { + ClassBase igen = SymbolTable.Table.GetClassGen (iface); + if (igen == null) + continue; + p = igen.GetMethodRecursively (name, true); + if (p != null) + break; + } + } + + return p; + } + + public virtual Property GetPropertyRecursively (string name) + { + ClassBase klass = this; + Property p = null; + while (klass != null && p == null) { + p = (Property) klass.GetProperty (name); + klass = klass.Parent; + } + + return p; + } + + public bool Implements (string iface) + { + if (interfaces.Contains (iface)) + return true; + else if (Parent != null) + return Parent.Implements (iface); + else + return false; + } + + public ArrayList Ctors { get { return ctors; } } + + bool HasStaticCtor (string name) + { + if (Parent != null && Parent.HasStaticCtor (name)) + return true; + + foreach (Ctor ctor in Ctors) + if (ctor.StaticName == name) + return true; + + return false; + } + + private void InitializeCtors () + { + if (ctors_initted) + return; + + if (Parent != null) + Parent.InitializeCtors (); + + ArrayList valid_ctors = new ArrayList(); + clash_map = new Hashtable(); + + foreach (Ctor ctor in ctors) { + if (clash_map.Contains (ctor.Signature.Types)) { + Ctor clash = clash_map [ctor.Signature.Types] as Ctor; + Ctor alter = ctor.Preferred ? clash : ctor; + alter.IsStatic = true; + if (Parent != null && Parent.HasStaticCtor (alter.StaticName)) + alter.Modifiers = "new "; + } else + clash_map [ctor.Signature.Types] = ctor; + + valid_ctors.Add (ctor); + } + + ctors = valid_ctors; + ctors_initted = true; + } + + protected virtual void GenCtors (GenerationInfo gen_info) + { + InitializeCtors (); + foreach (Ctor ctor in ctors) + ctor.Generate (gen_info); + } + + public virtual void Finish (StreamWriter sw, string indent) + { + } + + public virtual void Prepare (StreamWriter sw, string indent) + { + } + } +} diff --git a/generator/ClassField.cs b/generator/ClassField.cs new file mode 100644 index 0000000000..e5276d42bf --- /dev/null +++ b/generator/ClassField.cs @@ -0,0 +1,43 @@ +// GtkSharp.Generation.ClassField.cs - used in class structures +// +// Copyright (c) 2009 Christian Hoff +// +// 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.Collections; + using System.IO; + using System.Xml; + + public class ClassField : StructField { + protected new ObjectBase container_type; + + public ClassField (XmlElement elem, ObjectBase container_type) : base (elem, container_type) { + this.container_type = container_type; + } + + public override bool Validate () { + if (IsBitfield) { + Console.WriteLine ("Field {0}.{1} is a bitfield which is not supported yet", container_type.ClassStructName, Name); + return false; + } + + return base.Validate (); + } + } +} diff --git a/generator/ClassGen.cs b/generator/ClassGen.cs new file mode 100644 index 0000000000..700a27a1e4 --- /dev/null +++ b/generator/ClassGen.cs @@ -0,0 +1,94 @@ +// GtkSharp.Generation.ClassGen.cs - The Class Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// +// 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.Collections; + using System.IO; + using System.Text; + using System.Xml; + + public class ClassGen : ClassBase { + + public ClassGen (XmlElement ns, XmlElement elem) : base (ns, elem) {} + + public override string AssignToName { + get { + return String.Empty; + } + } + + public override string MarshalType { + get { + return String.Empty; + } + } + + public override string CallByName () + { + return String.Empty; + } + + public override string CallByName (string var) + { + return String.Empty; + } + + public override string FromNative (string var) + { + return String.Empty; + } + + public override void Generate (GenerationInfo gen_info) + { + gen_info.CurrentType = Name; + + StreamWriter sw = gen_info.Writer = gen_info.OpenStream(Name); + + sw.WriteLine ("namespace " + NS + " {"); + sw.WriteLine (); + sw.WriteLine ("\tusing System;"); + sw.WriteLine ("\tusing System.Runtime.InteropServices;"); + sw.WriteLine (); + + sw.WriteLine ("#region Autogenerated code"); + if (IsDeprecated) + sw.WriteLine ("\t[Obsolete]"); + sw.Write ("\t{0} class " + Name, IsInternal ? "internal" : "public"); + sw.WriteLine (" {"); + sw.WriteLine (); + + GenProperties (gen_info, null); + GenMethods (gen_info, null, null); + + sw.WriteLine ("#endregion"); + AppendCustom(sw, gen_info.CustomDir); + + sw.WriteLine ("\t}"); + sw.WriteLine ("}"); + + sw.Close (); + gen_info.Writer = null; + } + } +} + diff --git a/generator/CodeGenerator.cs b/generator/CodeGenerator.cs new file mode 100644 index 0000000000..f45c7a0efa --- /dev/null +++ b/generator/CodeGenerator.cs @@ -0,0 +1,122 @@ +// GtkSharp.Generation.CodeGenerator.cs - The main code generation engine. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// Copyright (c) 2003-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.Collections; + using System.Xml; + + public class CodeGenerator { + + public static int Main (string[] args) + { + if (args.Length < 2) { + Console.WriteLine ("Usage: codegen --generate "); + return 0; + } + + bool generate = false; + string dir = ""; + string custom_dir = ""; + string assembly_name = ""; + string glue_filename = ""; + string glue_includes = ""; + string gluelib_name = ""; + + SymbolTable table = SymbolTable.Table; + ArrayList gens = new ArrayList (); + foreach (string arg in args) { + string filename = arg; + if (arg == "--generate") { + generate = true; + continue; + } else if (arg == "--include") { + generate = false; + continue; + } else if (arg.StartsWith ("-I:")) { + generate = false; + filename = filename.Substring (3); + } else if (arg.StartsWith ("--outdir=")) { + generate = false; + dir = arg.Substring (9); + continue; + } else if (arg.StartsWith ("--customdir=")) { + generate = false; + custom_dir = arg.Substring (12); + continue; + } else if (arg.StartsWith ("--assembly-name=")) { + generate = false; + assembly_name = arg.Substring (16); + continue; + } else if (arg.StartsWith ("--glue-filename=")) { + generate = false; + glue_filename = arg.Substring (16); + continue; + } else if (arg.StartsWith ("--glue-includes=")) { + generate = false; + glue_includes = arg.Substring (16); + continue; + } else if (arg.StartsWith ("--gluelib-name=")) { + generate = false; + gluelib_name = arg.Substring (15); + continue; + } + + Parser p = new Parser (); + IGeneratable[] curr_gens = p.Parse (filename); + table.AddTypes (curr_gens); + if (generate) + gens.AddRange (curr_gens); + } + + // Now that everything is loaded, validate all the to-be- + // generated generatables and then remove the invalid ones. + ArrayList invalids = new ArrayList (); + foreach (IGeneratable gen in gens) { + if (!gen.Validate ()) + invalids.Add (gen); + } + foreach (IGeneratable gen in invalids) + gens.Remove (gen); + + GenerationInfo gen_info = null; + if (dir != "" || assembly_name != "" || glue_filename != "" || glue_includes != "" || gluelib_name != "") + gen_info = new GenerationInfo (dir, custom_dir, assembly_name, glue_filename, glue_includes, gluelib_name); + + foreach (IGeneratable gen in gens) { + if (gen_info == null) + gen.Generate (); + else + gen.Generate (gen_info); + } + + ObjectGen.GenerateMappers (); + + if (gen_info != null) + gen_info.CloseGlueWriter (); + + Statistics.Report(); + return 0; + } + } +} diff --git a/generator/ConstFilenameGen.cs b/generator/ConstFilenameGen.cs new file mode 100644 index 0000000000..562ab9ce14 --- /dev/null +++ b/generator/ConstFilenameGen.cs @@ -0,0 +1,52 @@ +// ConstFilenameGen.cs - The Const Filename type Generatable. +// +// Author: 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 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; + + public class ConstFilenameGen : SimpleBase, IManualMarshaler { + + public ConstFilenameGen (string ctype) : base (ctype, "string", "null") {} + + public override string MarshalType { + get { + return "IntPtr"; + } + } + + public override string FromNative (string var) + { + return "GLib.Marshaller.FilenamePtrToString (" + var + ")"; + } + + public string AllocNative (string managed_var) + { + return "GLib.Marshaller.StringToFilenamePtr (" + managed_var + ")"; + } + + public string ReleaseNative (string native_var) + { + return "GLib.Marshaller.Free (" + native_var + ")"; + } + } +} + diff --git a/generator/ConstStringGen.cs b/generator/ConstStringGen.cs new file mode 100644 index 0000000000..70f882ef25 --- /dev/null +++ b/generator/ConstStringGen.cs @@ -0,0 +1,59 @@ +// GtkSharp.Generation.ConstStringGen.cs - The Const String type Generatable. +// +// Author: Rachel Hestilow +// Mike Kestner +// +// Copyright (c) 2003 Rachel Hestilow +// 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 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; + + public class ConstStringGen : SimpleBase, IManualMarshaler { + + public ConstStringGen (string ctype) : base (ctype, "string", "null") {} + + public override string MarshalType { + get { + return "IntPtr"; + } + } + + public override string FromNative (string var) + { + return "GLib.Marshaller.Utf8PtrToString (" + var + ")"; + } + + public override string ToNativeReturn (string var) + { + return "GLib.Marshaller.StringToPtrGStrdup (" + var + ")"; + } + + public string AllocNative (string managed_var) + { + return "GLib.Marshaller.StringToPtrGStrdup (" + managed_var + ")"; + } + + public string ReleaseNative (string native_var) + { + return "GLib.Marshaller.Free (" + native_var + ")"; + } + } +} + diff --git a/generator/Ctor.cs b/generator/Ctor.cs new file mode 100644 index 0000000000..776b084c33 --- /dev/null +++ b/generator/Ctor.cs @@ -0,0 +1,168 @@ +// GtkSharp.Generation.Ctor.cs - The Constructor Generation Class. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// Copyright (c) 2004-2005 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.Collections; + using System.IO; + using System.Xml; + + public class Ctor : MethodBase { + + private bool preferred; + private string name; + private bool needs_chaining = false; + + public Ctor (XmlElement elem, ClassBase implementor) : base (elem, implementor) + { + if (elem.HasAttribute ("preferred")) + preferred = true; + if (implementor is ObjectGen) + needs_chaining = true; + name = implementor.Name; + } + + public bool Preferred { + get { return preferred; } + set { preferred = value; } + } + + public string StaticName { + get { + if (!IsStatic) + return String.Empty; + + if (Name != null && Name != String.Empty) + return Name; + + string[] toks = CName.Substring(CName.IndexOf("new")).Split ('_'); + string result = String.Empty; + + foreach (string tok in toks) + result += tok.Substring(0,1).ToUpper() + tok.Substring(1); + return result; + } + } + + void GenerateImport (StreamWriter sw) + { + sw.WriteLine("\t\t[DllImport(\"" + LibraryName + "\")]"); + sw.WriteLine("\t\tstatic extern " + Safety + "IntPtr " + CName + "(" + Parameters.ImportSignature + ");"); + sw.WriteLine(); + } + + void GenerateStatic (GenerationInfo gen_info) + { + StreamWriter sw = gen_info.Writer; + sw.WriteLine("\t\t" + Protection + " static " + Safety + Modifiers + name + " " + StaticName + "(" + Signature + ")"); + sw.WriteLine("\t\t{"); + + Body.Initialize(gen_info, false, false, ""); + + sw.Write("\t\t\t" + name + " result = "); + if (container_type is StructBase) + sw.Write ("{0}.New (", name); + else + sw.Write ("new {0} (", name); + sw.WriteLine (CName + "(" + Body.GetCallString (false) + "));"); + Body.Finish (sw, ""); + Body.HandleException (sw, ""); + sw.WriteLine ("\t\t\treturn result;"); + } + + public void Generate (GenerationInfo gen_info) + { + if (!Validate ()) + return; + + StreamWriter sw = gen_info.Writer; + gen_info.CurrentMember = CName; + + GenerateImport (sw); + + if (IsStatic) + GenerateStatic (gen_info); + else { + sw.WriteLine("\t\t{0} {1}{2} ({3}) {4}", Protection, Safety, name, Signature.ToString(), needs_chaining ? ": base (IntPtr.Zero)" : ""); + sw.WriteLine("\t\t{"); + + if (needs_chaining) { + sw.WriteLine ("\t\t\tif (GetType () != typeof (" + name + ")) {"); + + if (Parameters.Count == 0) { + sw.WriteLine ("\t\t\t\tCreateNativeObject (new string [0], new GLib.Value[0]);"); + sw.WriteLine ("\t\t\t\treturn;"); + } else { + ArrayList names = new ArrayList (); + ArrayList values = new ArrayList (); + for (int i = 0; i < Parameters.Count; i++) { + Parameter p = Parameters[i]; + if (container_type.GetPropertyRecursively (p.StudlyName) != null) { + names.Add (p.Name); + values.Add (p.Name); + } else if (p.PropertyName != String.Empty) { + names.Add (p.PropertyName); + values.Add (p.Name); + } + } + + if (names.Count == Parameters.Count) { + sw.WriteLine ("\t\t\t\tArrayList vals = new ArrayList();"); + sw.WriteLine ("\t\t\t\tArrayList names = new ArrayList();"); + for (int i = 0; i < names.Count; i++) { + Parameter p = Parameters [i]; + string indent = "\t\t\t\t"; + if (p.Generatable is ClassBase && !(p.Generatable is StructBase)) { + sw.WriteLine (indent + "if (" + p.Name + " != null) {"); + indent += "\t"; + } + sw.WriteLine (indent + "names.Add (\"" + names [i] + "\");"); + sw.WriteLine (indent + "vals.Add (new GLib.Value (" + values[i] + "));"); + + if (p.Generatable is ClassBase && !(p.Generatable is StructBase)) + sw.WriteLine ("\t\t\t\t}"); + } + + sw.WriteLine ("\t\t\t\tCreateNativeObject ((string[])names.ToArray (typeof (string)), (GLib.Value[])vals.ToArray (typeof (GLib.Value)));"); + sw.WriteLine ("\t\t\t\treturn;"); + } else + sw.WriteLine ("\t\t\t\tthrow new InvalidOperationException (\"Can't override this constructor.\");"); + } + + sw.WriteLine ("\t\t\t}"); + } + + Body.Initialize(gen_info, false, false, ""); + sw.WriteLine("\t\t\t{0} = {1}({2});", container_type.AssignToName, CName, Body.GetCallString (false)); + Body.Finish (sw, ""); + Body.HandleException (sw, ""); + } + + sw.WriteLine("\t\t}"); + sw.WriteLine(); + + Statistics.CtorCount++; + } + } +} + diff --git a/generator/DefaultSignalHandler.cs b/generator/DefaultSignalHandler.cs new file mode 100644 index 0000000000..989310808b --- /dev/null +++ b/generator/DefaultSignalHandler.cs @@ -0,0 +1,146 @@ +// GtkSharp.Generation.DefaultSignalHandler.cs - The default signal handler generatable +// +// Author: Christian Hoff +// +// Copyright (c) 2008 Novell Inc. +// Copyright (c) 2008-2009 Christian Hoff +// +// 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 DefaultSignalHandler : GObjectVM { + private string signal_name; + + public DefaultSignalHandler (XmlElement elem, ObjectBase container_type) : base (elem, container_type) + { + signal_name = elem.GetAttribute ("cname"); + } + + public override string CName { + get { + return elem.GetAttribute ("field_name"); + } + } + + protected override bool CanGenerate (GenerationInfo gen_info, ObjectBase implementor) + { + return true; + } + + protected override void GenerateOverride (GenerationInfo gen_info, ObjectBase implementor) + { + StreamWriter sw = gen_info.Writer; + + if (!base.CanGenerate (gen_info, implementor)) { + GenerateOverrideBody (sw); + sw.WriteLine ("\t\t\tOverrideVirtualMethod (gtype, \"{0}\", callback);", signal_name); + sw.WriteLine ("\t\t}"); + } else + base.GenerateOverride (gen_info, implementor); + } + + protected override void GenerateUnmanagedInvocation (GenerationInfo gen_info, ObjectBase implementor) + { + if (!base.CanGenerate (gen_info, implementor)) + GenerateChainVirtualMethod (gen_info.Writer, implementor); + else + base.GenerateUnmanagedInvocation (gen_info, implementor); + } + + private void GenerateChainVirtualMethod (StreamWriter sw, ObjectBase implementor) + { + GenerateMethodBody (sw, implementor); + if (retval.IsVoid) + sw.WriteLine ("\t\t\tGLib.Value ret = GLib.Value.Empty;"); + else + sw.WriteLine ("\t\t\tGLib.Value ret = new GLib.Value (" + ReturnGType + ");"); + + sw.WriteLine ("\t\t\tGLib.ValueArray inst_and_params = new GLib.ValueArray (" + (parms.Count + 1) + ");"); + sw.WriteLine ("\t\t\tGLib.Value[] vals = new GLib.Value [" + (parms.Count + 1) + "];"); + sw.WriteLine ("\t\t\tvals [0] = new GLib.Value (this);"); + sw.WriteLine ("\t\t\tinst_and_params.Append (vals [0]);"); + string cleanup = ""; + for (int i = 0; i < parms.Count; i++) { + Parameter p = parms [i]; + if (p.PassAs != "") { + if (SymbolTable.Table.IsBoxed (p.CType)) { + if (p.PassAs == "ref") + sw.WriteLine ("\t\t\tvals [" + (i + 1) + "] = new GLib.Value (" + p.Name + ");"); + else + sw.WriteLine ("\t\t\tvals [" + (i + 1) + "] = new GLib.Value ((GLib.GType)typeof (" + p.CSType + "));"); + cleanup += "\t\t\t" + p.Name + " = (" + p.CSType + ") vals [" + i + "];\n"; + } else { + if (p.PassAs == "ref") + sw.WriteLine ("\t\t\tIntPtr " + p.Name + "_ptr = GLib.Marshaller.StructureToPtrAlloc (" + p.Generatable.CallByName (p.Name) + ");"); + else + sw.WriteLine ("\t\t\tIntPtr " + p.Name + "_ptr = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (" + p.MarshalType + ")));"); + + sw.WriteLine ("\t\t\tvals [" + (i + 1) + "] = new GLib.Value (" + p.Name + "_ptr);"); + cleanup += "\t\t\t" + p.Name + " = " + p.FromNative ("(" + p.MarshalType + ") Marshal.PtrToStructure (" + p.Name + "_ptr, typeof (" + p.MarshalType + "))") + ";\n"; + cleanup += "\t\t\tMarshal.FreeHGlobal (" + p.Name + "_ptr);\n"; + } + } else if (p.IsLength && i > 0 && parms [i - 1].IsString) + sw.WriteLine ("\t\t\tvals [" + (i + 1) + "] = new GLib.Value (System.Text.Encoding.UTF8.GetByteCount (" + parms [i-1].Name + "));"); + else + sw.WriteLine ("\t\t\tvals [" + (i + 1) + "] = new GLib.Value (" + p.Name + ");"); + + sw.WriteLine ("\t\t\tinst_and_params.Append (vals [" + (i + 1) + "]);"); + } + + sw.WriteLine ("\t\t\tg_signal_chain_from_overridden (inst_and_params.ArrayPtr, ref ret);"); + if (cleanup != "") + sw.WriteLine (cleanup); + sw.WriteLine ("\t\t\tforeach (GLib.Value v in vals)"); + sw.WriteLine ("\t\t\t\tv.Dispose ();"); + if (!retval.IsVoid) { + IGeneratable igen = SymbolTable.Table [retval.CType]; + sw.WriteLine ("\t\t\t" + retval.CSType + " result = (" + (igen is EnumGen ? retval.CSType + ") (Enum" : retval.CSType) + ") ret;"); + sw.WriteLine ("\t\t\tret.Dispose ();"); + sw.WriteLine ("\t\t\treturn result;"); + } + sw.WriteLine ("\t\t}\n"); + } + + private string ReturnGType { + get { + IGeneratable igen = SymbolTable.Table [retval.CType]; + + if (igen is ObjectGen) + return "GLib.GType.Object"; + if (igen is BoxedGen) + return retval.CSType + ".GType"; + if (igen is EnumGen) + return retval.CSType + "GType.GType"; + + switch (retval.CSType) { + case "bool": + return "GLib.GType.Boolean"; + case "string": + return "GLib.GType.String"; + case "int": + return "GLib.GType.Int"; + default: + throw new Exception (retval.CSType); + } + } + } + } +} + diff --git a/generator/EnumGen.cs b/generator/EnumGen.cs new file mode 100644 index 0000000000..2be39b5582 --- /dev/null +++ b/generator/EnumGen.cs @@ -0,0 +1,132 @@ +// GtkSharp.Generation.EnumGen.cs - The Enumeration Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2001 Mike Kestner +// +// 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.Collections; + using System.IO; + using System.Xml; + + public class EnumGen : GenBase { + + string enum_type = String.Empty; + ArrayList members = new ArrayList (); + + public EnumGen (XmlElement ns, XmlElement elem) : base (ns, elem) + { + foreach (XmlElement member in elem.ChildNodes) { + if (member.Name != "member") + continue; + + string result = "\t\t" + member.GetAttribute("name"); + if (member.HasAttribute("value")) { + string value = member.GetAttribute("value"); + if (value.EndsWith("U")) { + enum_type = " : uint"; + value = value.TrimEnd('U'); + } else if (value.EndsWith("L")) { + enum_type = " : long"; + value = value.TrimEnd('L'); + } + result += " = " + value; + } + members.Add (result + ","); + } + if (elem.HasAttribute ("enum_type")) + enum_type = ": " + elem.GetAttribute ("enum_type"); + } + + public override bool Validate () + { + return true; + } + + public override string DefaultValue { + get { + return "(" + QualifiedName + ") 0"; + } + } + + public override string MarshalType { + get { + return "int"; + } + } + + public override string CallByName (string var_name) + { + return "(int) " + var_name; + } + + public override string FromNative(string var) + { + return "(" + QualifiedName + ") " + var; + } + + public override void Generate (GenerationInfo gen_info) + { + StreamWriter sw = gen_info.OpenStream (Name); + + sw.WriteLine ("namespace " + NS + " {"); + sw.WriteLine (); + sw.WriteLine ("\tusing System;"); + sw.WriteLine ("\tusing System.Runtime.InteropServices;"); + sw.WriteLine (); + + sw.WriteLine ("#region Autogenerated code"); + + if (Elem.GetAttribute("type") == "flags") + sw.WriteLine ("\t[Flags]"); + if (Elem.HasAttribute("gtype")) + sw.WriteLine ("\t[GLib.GType (typeof (" + NS + "." + Name + "GType))]"); + + string access = IsInternal ? "internal" : "public"; + sw.WriteLine ("\t" + access + " enum " + Name + enum_type + " {"); + sw.WriteLine (); + + foreach (string member in members) + sw.WriteLine (member); + + sw.WriteLine ("\t}"); + + if (Elem.HasAttribute ("gtype")) { + sw.WriteLine (); + sw.WriteLine ("\tinternal class " + Name + "GType {"); + sw.WriteLine ("\t\t[DllImport (\"" + LibraryName + "\")]"); + sw.WriteLine ("\t\tstatic extern IntPtr " + Elem.GetAttribute ("gtype") + " ();"); + sw.WriteLine (); + sw.WriteLine ("\t\tpublic static GLib.GType GType {"); + sw.WriteLine ("\t\t\tget {"); + sw.WriteLine ("\t\t\t\treturn new GLib.GType (" + Elem.GetAttribute ("gtype") + " ());"); + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine ("\t}"); + } + + sw.WriteLine ("#endregion"); + sw.WriteLine ("}"); + sw.Close (); + Statistics.EnumCount++; + } + } +} + diff --git a/generator/FieldBase.cs b/generator/FieldBase.cs new file mode 100644 index 0000000000..81690271e8 --- /dev/null +++ b/generator/FieldBase.cs @@ -0,0 +1,271 @@ +// GtkSharp.Generation.FieldBase.cs - base class for struct and object +// fields +// +// 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.Collections; + using System.IO; + using System.Xml; + + public abstract class FieldBase : PropertyBase { + public FieldBase (XmlElement elem, ClassBase container_type) : base (elem, container_type) {} + + public virtual bool Validate () + { + if (!Ignored && !Hidden && CSType == "") { + Console.Write("Field {0} has unknown Type {1} ", Name, CType); + Statistics.ThrottledCount++; + return false; + } + + return true; + } + + protected virtual bool Readable { + get { + return elem.GetAttribute ("readable") != "false"; + } + } + + protected virtual bool Writable { + get { + return elem.GetAttribute ("writeable") != "false"; + } + } + + protected abstract string DefaultAccess { get; } + + protected string Access { + get { + return elem.HasAttribute ("access") ? elem.GetAttribute ("access") : DefaultAccess; + } + } + + public bool IsArray { + get { + return elem.HasAttribute("array_len") || elem.HasAttribute("array"); + } + } + + public bool IsBitfield { + get { + return elem.HasAttribute("bits"); + } + } + + public bool Ignored { + get { + if (container_type.GetProperty (Name) != null) + return true; + if (IsArray) + return true; + if (Access == "private" && (Getter == null) && (Setter == null)) + return true; + return false; + } + } + + string getterName, setterName; + string getOffsetName, offsetName; + + void CheckGlue () + { + getterName = setterName = getOffsetName = null; + if (DefaultAccess != "public" && (!elem.HasAttribute ("access") || (Access != "public" && Access != "protected" && Access != "internal"))) + return; + + string prefix = (container_type.NS + "Sharp_" + container_type.NS + "_" + container_type.Name).Replace(".", "__").ToLower (); + + if (IsBitfield) { + if (Readable && Getter == null) + getterName = prefix + "_get_" + CName; + if (Writable && Setter == null) + setterName = prefix + "_set_" + CName; + } else { + if ((Readable && Getter == null) || (Writable && Setter == null)) { + offsetName = CName + "_offset"; + getOffsetName = prefix + "_get_" + offsetName; + } + } + } + + protected override void GenerateImports (GenerationInfo gen_info, string indent) + { + StreamWriter sw = gen_info.Writer; + SymbolTable table = SymbolTable.Table; + + if (getterName != null) { + sw.WriteLine (indent + "[DllImport (\"{0}\")]", gen_info.GluelibName); + sw.WriteLine (indent + "extern static {0} {1} ({2} raw);", + table.GetMarshalReturnType (CType), getterName, + container_type.MarshalType); + } + + if (setterName != null) { + sw.WriteLine (indent + "[DllImport (\"{0}\")]", gen_info.GluelibName); + sw.WriteLine (indent + "extern static void {0} ({1} raw, {2} value);", + setterName, container_type.MarshalType, table.GetMarshalType (CType)); + } + + if (getOffsetName != null) { + sw.WriteLine (indent + "[DllImport (\"{0}\")]", gen_info.GluelibName); + sw.WriteLine (indent + "extern static uint {0} ();", getOffsetName); + sw.WriteLine (); + sw.WriteLine (indent + "static uint " + offsetName + " = " + getOffsetName + " ();"); + } + + base.GenerateImports (gen_info, indent); + } + + public virtual void Generate (GenerationInfo gen_info, string indent) + { + if (Ignored || Hidden) + return; + + CheckGlue (); + if ((getterName != null || setterName != null || getOffsetName != null) && + gen_info.GlueWriter == null) { + Console.WriteLine ("No glue-filename specified, can't create glue for {0}.{1}", + container_type.Name, Name); + return; + } + + GenerateImports (gen_info, indent); + + SymbolTable table = SymbolTable.Table; + StreamWriter sw = gen_info.Writer; + string modifiers = elem.HasAttribute ("new_flag") ? "new " : ""; + bool is_struct = table.IsStruct (CType) || table.IsBoxed (CType); + string access = elem.HasAttribute ("access") ? elem.GetAttribute ("access") : "public"; + + sw.WriteLine (indent + access + " " + modifiers + CSType + " " + Name + " {"); + + if (Getter != null) { + sw.Write (indent + "\tget "); + Getter.GenerateBody (gen_info, container_type, "\t"); + sw.WriteLine (""); + } else if (getterName != null) { + sw.WriteLine (indent + "\tget {"); + container_type.Prepare (sw, indent + "\t\t"); + sw.WriteLine (indent + "\t\t" + CSType + " result = " + table.FromNativeReturn (ctype, getterName + " (" + container_type.CallByName () + ")") + ";"); + container_type.Finish (sw, indent + "\t\t"); + sw.WriteLine (indent + "\t\treturn result;"); + sw.WriteLine (indent + "\t}"); + } else if (Readable && offsetName != null) { + sw.WriteLine (indent + "\tget {"); + sw.WriteLine (indent + "\t\tunsafe {"); + if (is_struct) { + sw.WriteLine (indent + "\t\t\t" + CSType + "* raw_ptr = (" + CSType + "*)(((byte*)" + container_type.CallByName () + ") + " + offsetName + ");"); + sw.WriteLine (indent + "\t\t\treturn *raw_ptr;"); + } else { + sw.WriteLine (indent + "\t\t\t" + table.GetMarshalReturnType (CType) + "* raw_ptr = (" + table.GetMarshalReturnType (CType) + "*)(((byte*)" + container_type.CallByName () + ") + " + offsetName + ");"); + sw.WriteLine (indent + "\t\t\treturn " + table.FromNativeReturn (ctype, "(*raw_ptr)") + ";"); + } + sw.WriteLine (indent + "\t\t}"); + sw.WriteLine (indent + "\t}"); + } + + if (Setter != null) { + sw.Write (indent + "\tset "); + Setter.GenerateBody (gen_info, container_type, "\t"); + sw.WriteLine (""); + } else if (setterName != null) { + sw.WriteLine (indent + "\tset {"); + container_type.Prepare (sw, indent + "\t\t"); + sw.WriteLine (indent + "\t\t" + setterName + " (" + container_type.CallByName () + ", " + table.CallByName (ctype, "value") + ");"); + container_type.Finish (sw, indent + "\t\t"); + sw.WriteLine (indent + "\t}"); + } else if (Writable && offsetName != null) { + sw.WriteLine (indent + "\tset {"); + sw.WriteLine (indent + "\t\tunsafe {"); + if (is_struct) { + sw.WriteLine (indent + "\t\t\t" + CSType + "* raw_ptr = (" + CSType + "*)(((byte*)" + container_type.CallByName () + ") + " + offsetName + ");"); + sw.WriteLine (indent + "\t\t\t*raw_ptr = value;"); + } else { + sw.WriteLine (indent + "\t\t\t" + table.GetMarshalReturnType (CType) + "* raw_ptr = (" + table.GetMarshalReturnType (CType) + "*)(((byte*)" + container_type.CallByName () + ") + " + offsetName + ");"); + sw.WriteLine (indent + "\t\t\t*raw_ptr = " + table.ToNativeReturn (ctype, "value") + ";"); + } + sw.WriteLine (indent + "\t\t}"); + sw.WriteLine (indent + "\t}"); + } + + sw.WriteLine (indent + "}"); + sw.WriteLine (""); + + if (getterName != null || setterName != null || getOffsetName != null) + GenerateGlue (gen_info); + } + + protected void GenerateGlue (GenerationInfo gen_info) + { + StreamWriter sw = gen_info.GlueWriter; + SymbolTable table = SymbolTable.Table; + + string FieldCType = CType.Replace ("-", " "); + bool byref = table[CType] is ByRefGen || table[CType] is StructGen; + string GlueCType = byref ? FieldCType + " *" : FieldCType; + string ContainerCType = container_type.CName; + string ContainerCName = container_type.Name.ToLower (); + + if (getterName != null) { + sw.WriteLine ("{0} {1} ({2} *{3});", + GlueCType, getterName, ContainerCType, ContainerCName); + } + if (setterName != null) { + sw.WriteLine ("void {0} ({1} *{2}, {3} value);", + setterName, ContainerCType, ContainerCName, GlueCType); + } + if (getOffsetName != null) + sw.WriteLine ("guint {0} (void);", getOffsetName); + sw.WriteLine (""); + + if (getterName != null) { + sw.WriteLine (GlueCType); + sw.WriteLine ("{0} ({1} *{2})", getterName, ContainerCType, ContainerCName); + sw.WriteLine ("{"); + sw.WriteLine ("\treturn ({0}){1}{2}->{3};", GlueCType, + byref ? "&" : "", ContainerCName, CName); + sw.WriteLine ("}"); + sw.WriteLine (""); + } + if (setterName != null) { + sw.WriteLine ("void"); + sw.WriteLine ("{0} ({1} *{2}, {3} value)", + setterName, ContainerCType, ContainerCName, GlueCType); + sw.WriteLine ("{"); + sw.WriteLine ("\t{0}->{1} = ({2}){3}value;", ContainerCName, CName, + FieldCType, byref ? "*" : ""); + sw.WriteLine ("}"); + sw.WriteLine (""); + } + if (getOffsetName != null) { + sw.WriteLine ("guint"); + sw.WriteLine ("{0} (void)", getOffsetName); + sw.WriteLine ("{"); + sw.WriteLine ("\treturn (guint)G_STRUCT_OFFSET ({0}, {1});", + ContainerCType, CName); + sw.WriteLine ("}"); + sw.WriteLine (""); + } + } + } +} + diff --git a/generator/GObjectVM.cs b/generator/GObjectVM.cs new file mode 100644 index 0000000000..da89fb3156 --- /dev/null +++ b/generator/GObjectVM.cs @@ -0,0 +1,368 @@ +// GtkSharp.Generation.GObjectVM.cs - GObject specific part of VM creation +// +// Author: Christian Hoff +// +// Copyright (c) 2007 Novell, Inc. +// Copyright (c) 2009 Christian Hoff +// +// 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.Collections; + using System.IO; + using System.Xml; + + public class GObjectVM : VirtualMethod + { + protected string class_struct_name; + const bool force_glue_generation = false; + + public GObjectVM (XmlElement elem, ObjectBase container_type) : base (elem, container_type) + { + parms.HideData = false; + this.Protection = "protected"; + class_struct_name = container_type.ClassStructName; + } + + // Some types don't install headers. In that case, the glue code will not compile. + bool BlockGlue { + get { + return elem.GetAttribute ("block_glue") == "1"; + } + } + + protected override string CallString { + get { + return String.Format ("{0} ({1})", IsStatic ? this.CName + "_handler" : "On" + this.Name, call.ToString ()); + } + } + + public void Generate (GenerationInfo gen_info, ObjectBase implementor) + { + if (!CanGenerate (gen_info, implementor)) + throw new NotSupportedException (String.Format ("Cannot generate virtual method {0}.{1}. Make sure a writable glue path was provided to the generator.", container_type.Name, this.CallString)); + + GenerateOverride (gen_info, implementor); + GenerateCallback (gen_info.Writer, implementor); + if (!IsStatic) + GenerateUnmanagedInvocation (gen_info, implementor); + } + + protected virtual bool CanGenerate (GenerationInfo gen_info, ObjectBase implementor) + { + if (implementor != null || this.CName.Length == 0 || CodeType == VMCodeType.None || (CodeType == VMCodeType.Glue && !gen_info.GlueEnabled)) + return false; + else + return true; + } + + enum VMCodeType { + None, + Managed, + Glue + } + + VMCodeType CodeType { + get { + if (!(container_type as ObjectBase).CanGenerateClassStruct || force_glue_generation) { + if (BlockGlue) + return VMCodeType.None; + else + return VMCodeType.Glue; + } else + return VMCodeType.Managed; + } + } + + enum VMOverrideType { + Unspecified, + DeclaringClass, + ImplementingClass + } + + /* There are basically two types of static virtual methods: + * 1. VMs overridden in the declaring class (e.g. AtkUtil vms): + * The VM is overridden in the class in which it is declared and not in the derived classes. In that case, the GAPI generates a static XYZHandler property + * in the declaring class. + * 2. VMs overridden in derived classes (e.g. GIO is_supported vms): + * As with nonstatic vms, this VM type hooks into the class structure field of derived classes. This type is currently unsupported as it is rarely used + * and we would need anonymous methods for the callback (we are using only *one* callback method; the callback does not know to which type that method call + * has to be redirected). + */ + VMOverrideType OverrideType { + get { + if (IsStatic) { + switch (elem.GetAttribute ("override_in")) { + case "declaring_class": + return VMOverrideType.DeclaringClass; + case "implementing_class": + return VMOverrideType.ImplementingClass; + default: + return VMOverrideType.Unspecified; + } + } else + return VMOverrideType.ImplementingClass; + } + } + + protected virtual void GenerateOverride (GenerationInfo gen_info, ObjectBase implementor) + { + if (CodeType == VMCodeType.Glue) + GenerateOverride_glue (gen_info); + else + GenerateOverride_managed (gen_info.Writer); + } + + protected virtual void GenerateUnmanagedInvocation (GenerationInfo gen_info, ObjectBase implementor) + { + if (CodeType == VMCodeType.Glue) + GenerateUnmanagedInvocation_glue (gen_info); + else + GenerateUnmanagedInvocation_managed (gen_info); + } + + protected void GenerateOverrideBody (StreamWriter sw) + { + sw.WriteLine ("\t\tstatic {0}NativeDelegate {0}_cb_delegate;", Name); + sw.WriteLine ("\t\tstatic " + Name + "NativeDelegate " + Name + "VMCallback {"); + sw.WriteLine ("\t\t\tget {"); + sw.WriteLine ("\t\t\t\tif ({0}_cb_delegate == null)", Name); + sw.WriteLine ("\t\t\t\t\t{0}_cb_delegate = new {0}NativeDelegate ({0}_cb);", Name); + sw.WriteLine ("\t\t\t\treturn {0}_cb_delegate;", Name); + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + if (IsStatic) { + sw.WriteLine ("\t\tpublic delegate {0} {1}Delegate ({2});", retval.CSType, Name, Signature.ToString ()); + sw.WriteLine ("\t\tstatic {0}Delegate {1}_handler;", Name, CName); + sw.WriteLine (); + sw.WriteLine ("\t\tpublic static " + Name + "Delegate " + Name + "Handler {"); + sw.WriteLine ("\t\t\tset {"); + sw.WriteLine ("\t\t\t\t{0}_handler = value;", CName); + sw.WriteLine ("\t\t\t\tOverride{0} ((GLib.GType) typeof ({1}), value == null ? null : {0}VMCallback);", Name, container_type.Name); + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + } else { + sw.WriteLine ("\t\tstatic void Override{0} (GLib.GType gtype)", this.Name); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tOverride{0} (gtype, {0}VMCallback);", this.Name); + sw.WriteLine ("\t\t}"); + } + sw.WriteLine (); + sw.WriteLine ("\t\tstatic void Override{0} (GLib.GType gtype, {0}NativeDelegate callback)", this.Name); + sw.WriteLine ("\t\t{"); + } + + protected void GenerateOverride_managed (StreamWriter sw) + { + GenerateOverrideBody (sw); + // Override VM; class_offset var is generated by object generatable + sw.WriteLine ("\t\t\t{0} class_iface = GetClassStruct (gtype, false);", class_struct_name); + sw.WriteLine ("\t\t\tclass_iface.{0} = callback;", this.Name); + sw.WriteLine ("\t\t\tOverrideClassStruct (gtype, class_iface);"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + protected void GenerateMethodBody (StreamWriter sw, ClassBase implementor) + { + sw.WriteLine ("\t\t[GLib.DefaultSignalHandler(Type=typeof(" + (implementor != null ? implementor.QualifiedName : container_type.QualifiedName) + "), ConnectionMethod=\"Override" + this.Name +"\")]"); + sw.Write ("\t\t{0} ", this.Protection); + if (this.modifiers != "") + sw.Write ("{0} ", this.modifiers); + sw.WriteLine ("virtual {0} On{1} ({2})", retval.CSType, this.Name, Signature.ToString ()); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\t{0}Internal{1} ({2});", retval.IsVoid ? "" : "return ", this.Name, Signature.GetCallString (false)); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + // This method is to be invoked from existing VM implementations in the .customs + sw.WriteLine ("\t\tprivate {0} Internal{1} ({2})", retval.CSType, this.Name, Signature.ToString ()); + sw.WriteLine ("\t\t{"); + } + + void GenerateUnmanagedInvocation_managed (GenerationInfo gen_info) + { + StreamWriter sw = gen_info.Writer; + string native_call = "this.Handle"; + if (parms.Count > 0) + native_call += ", " + Body.GetCallString (false); + + this.GenerateMethodBody (sw, null); + // Find the first unmanaged ancestor + sw.WriteLine ("\t\t\t{0}NativeDelegate unmanaged = GetClassStruct (this.LookupGType ().ThresholdType, true).{0};", this.Name); + sw.Write ("\t\t\tif (unmanaged == null) "); + if (parms.HasOutParam) + sw.WriteLine ("throw new InvalidOperationException (\"No base method to invoke\");"); + else if (retval.IsVoid) + sw.WriteLine ("return;"); + else + sw.WriteLine ("return {0};", retval.DefaultValue); + sw.WriteLine (); + Body.Initialize (gen_info); + sw.Write ("\t\t\t"); + if (!retval.IsVoid) + sw.Write ("{0} __result = ", retval.MarshalType); + sw.WriteLine ("unmanaged ({0});", native_call); + Body.Finish (gen_info.Writer, ""); + if(!retval.IsVoid) + sw.WriteLine ("\t\t\treturn {0};", retval.FromNative ("__result")); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + /* old glue code. This code is to be used if + * a) the generated api file is version 1 + * b) an old Mono version(< 2.4) is being used + * Punt it when we drop support for the parser version 1. + */ + + private string CastFromInt (string type) + { + return type != "int" ? "(" + type + ") " : ""; + } + + private string GlueSignature { + get { + string[] glue_params = new string [this.IsStatic ? parms.Count + 1 : parms.Count + 2]; + glue_params [0] = class_struct_name + " *class_struct"; + if (!IsStatic) + glue_params [1] = container_type.CName + "* inst"; + for (int i = 0; i < parms.Count; i++) + glue_params [i + (IsStatic ? 1 : 2)] = parms [i].CType.Replace ("const-", "const ") + " " + parms [i].Name; + return String.Join (", ", glue_params); + } + } + + private string DefaultGlueValue { + get { + if (retval.IGen is EnumGen) + return String.Format ("({0}) 0", retval.CType); + + string val = retval.DefaultValue; + switch (val) { + case "null": + return "NULL"; + case "false": + return "FALSE"; + case "true": + return "TRUE"; + case "GLib.GType.None": + return "G_TYPE_NONE"; + default: + return val; + } + } + } + + void GenerateOverride_glue (GenerationInfo gen_info) + { + StreamWriter glue = gen_info.GlueWriter; + StreamWriter sw = gen_info.Writer; + + string glue_name = String.Format ("{0}sharp_{1}_override_{2}", container_type.NS.ToLower ().Replace (".", "_"), container_type.Name.ToLower (), CName); + sw.WriteLine ("\t\t[DllImport (\"{0}\")]", gen_info.GluelibName); + sw.WriteLine ("\t\tstatic extern void {0} (IntPtr class_struct, {1}NativeDelegate cb);", glue_name, Name); + sw.WriteLine (); + glue.WriteLine ("void {0} ({1} *class_struct, gpointer cb);\n", glue_name, class_struct_name); + glue.WriteLine ("void\n{0} ({1} *class_struct, gpointer cb)", glue_name, class_struct_name); + glue.WriteLine ("{"); + glue.WriteLine ("\tclass_struct->{0} = cb;", CName); + glue.WriteLine ("}"); + glue.WriteLine (); + + GenerateOverrideBody (sw); + sw.WriteLine ("\t\t\t{0} (gtype.ClassPtr, callback);", glue_name); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + void GenerateUnmanagedInvocation_glue (GenerationInfo gen_info) + { + StreamWriter glue = gen_info.GlueWriter; + string glue_name = String.Format ("{0}sharp_{1}_invoke_{2}", container_type.NS.ToLower ().Replace (".", "_"), container_type.Name.ToLower (), CName); + + glue.WriteLine ("{0} {1} ({2});\n", retval.CType.Replace ("const-", "const "), glue_name, GlueSignature); + glue.WriteLine ("{0}\n{1} ({2})", retval.CType.Replace ("const-", "const "), glue_name, GlueSignature); + glue.WriteLine ("{"); + glue.Write ("\tif (class_struct->{0})\n\t\t", CName); + if (!retval.IsVoid) + glue.Write ("return "); + string[] call_args = new string [IsStatic ? parms.Count : parms.Count + 1]; + if (!IsStatic) + call_args [0] = "inst"; + for (int i = 0; i < parms.Count; i++) + call_args [IsStatic ? i : i + 1] = parms[i].Name; + glue.WriteLine ("(* class_struct->{0}) ({1});", CName, String.Join (", ", call_args)); + if (!retval.IsVoid) + glue.WriteLine ("\treturn " + DefaultGlueValue + ";"); + glue.WriteLine ("}"); + glue.WriteLine (); + + StreamWriter sw = gen_info.Writer; + sw.WriteLine ("\t\t[DllImport (\"{0}\")]", gen_info.GluelibName); + sw.Write ("\t\tstatic extern {0} {1} (IntPtr class_struct", retval.MarshalType, glue_name); + if (!IsStatic) + sw.Write (", IntPtr inst"); + if (parms.Count > 0) + sw.Write (", {0}", parms.ImportSignature); + sw.WriteLine (");"); + sw.WriteLine (); + + GenerateMethodBody (sw, null); + Body.Initialize (gen_info, false, false, String.Empty); + string glue_call_string = "this.LookupGType ().ThresholdType.ClassPtr"; + if (!IsStatic) + glue_call_string += ", Handle"; + if (parms.Count > 0) + glue_call_string += ", " + Body.GetCallString (false); + + sw.Write ("\t\t\t"); + if (!retval.IsVoid) + sw.Write ("{0} __result = ", retval.MarshalType); + sw.WriteLine ("{0} ({1});", glue_name, glue_call_string); + Body.Finish (gen_info.Writer, ""); + if(!retval.IsVoid) + sw.WriteLine ("\t\t\treturn {0};", retval.FromNative ("__result")); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + public override bool Validate () + { + if (!base.Validate ()) return false; + bool is_valid = true; + + if (this.IsStatic) { + switch (OverrideType) { + case VMOverrideType.Unspecified: + Console.Write ("Static virtual methods can only be generated if you provide info on how to override this method via the metadata "); + is_valid = false; + break; + case VMOverrideType.ImplementingClass: + Console.Write ("Overriding static virtual methods in the implementing class is not supported yet "); + is_valid = false; + break; + } + } + + if (!is_valid) + Console.WriteLine (" (in virtual method {0}.{1})", container_type.QualifiedName, this.Name); + return is_valid; + } + } +} diff --git a/generator/GenBase.cs b/generator/GenBase.cs new file mode 100644 index 0000000000..559e3e2031 --- /dev/null +++ b/generator/GenBase.cs @@ -0,0 +1,149 @@ +// GtkSharp.Generation.GenBase.cs - The Generatable base class. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2002 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 abstract class GenBase : IGeneratable { + + private XmlElement ns; + private XmlElement elem; + + protected GenBase (XmlElement ns, XmlElement elem) + { + this.ns = ns; + this.elem = elem; + } + + public string CName { + get { + return elem.GetAttribute ("cname"); + } + } + + public XmlElement Elem { + get { + return elem; + } + } + + public int ParserVersion { + get { + XmlElement root = elem.OwnerDocument.DocumentElement; + return root.HasAttribute ("parser_version") ? int.Parse (root.GetAttribute ("parser_version")) : 1; + } + } + + public bool IsInternal { + get { + if (elem.HasAttribute ("internal")) { + string attr = elem.GetAttribute ("internal"); + return attr == "1" || attr == "true"; + } + return false; + } + } + + public string LibraryName { + get { + return ns.GetAttribute ("library"); + } + } + + public virtual string MarshalReturnType { + get { + return MarshalType; + } + } + + public abstract string MarshalType { get; } + + public string Name { + get { + return elem.GetAttribute ("name"); + } + } + + public string NS { + get { + return ns.GetAttribute ("name"); + } + } + + public abstract string DefaultValue { get; } + + public string QualifiedName { + get { + return NS + "." + Name; + } + } + + public virtual string ToNativeReturnType { + get { + return MarshalType; + } + } + + protected void AppendCustom (StreamWriter sw, string custom_dir) + { + char sep = Path.DirectorySeparatorChar; + string custom = custom_dir + sep + Name + ".custom"; + if (File.Exists(custom)) { + sw.WriteLine ("#region Customized extensions"); + sw.WriteLine ("#line 1 \"" + Name + ".custom\""); + FileStream custstream = new FileStream(custom, FileMode.Open, FileAccess.Read); + StreamReader sr = new StreamReader(custstream); + sw.WriteLine (sr.ReadToEnd ()); + sw.WriteLine ("#endregion"); + sr.Close (); + } + } + + public abstract string CallByName (string var); + + public abstract string FromNative (string var); + + public virtual string FromNativeReturn (string var) + { + return FromNative (var); + } + + public virtual string ToNativeReturn (string var) + { + return CallByName (var); + } + + public abstract bool Validate (); + + public void Generate () + { + GenerationInfo geninfo = new GenerationInfo (ns); + Generate (geninfo); + } + + public abstract void Generate (GenerationInfo geninfo); + } +} + diff --git a/generator/GenerationInfo.cs b/generator/GenerationInfo.cs new file mode 100644 index 0000000000..a7fc74ee35 --- /dev/null +++ b/generator/GenerationInfo.cs @@ -0,0 +1,176 @@ +// GtkSharp.Generation.GenerationInfo.cs - Generation information class. +// +// Author: Mike Kestner +// +// Copyright (c) 2003-2008 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.Collections; + using System.IO; + using System.Xml; + + public class GenerationInfo { + + string dir; + string custom_dir; + string assembly_name; + string gluelib_name; + bool glue_enabled; + StreamWriter sw; + StreamWriter glue_sw; + + public GenerationInfo (XmlElement ns) + { + string ns_name = ns.GetAttribute ("name"); + char sep = Path.DirectorySeparatorChar; + dir = ".." + sep + ns_name.ToLower () + sep + "generated"; + custom_dir = ".." + sep + ns_name.ToLower (); + assembly_name = ns_name.ToLower () + "-sharp"; + } + + public GenerationInfo (string dir, string assembly_name) : this (dir, dir, assembly_name, "", "", "") {} + + public GenerationInfo (string dir, string custom_dir, string assembly_name, string glue_filename, string glue_includes, string gluelib_name) + { + this.dir = dir; + this.custom_dir = custom_dir; + this.assembly_name = assembly_name; + this.gluelib_name = gluelib_name; + InitializeGlue (glue_filename, glue_includes, gluelib_name); + } + + void InitializeGlue (string glue_filename, string glue_includes, string gluelib_name) + { + if (gluelib_name != String.Empty && glue_filename != String.Empty) { + FileStream stream; + try { + stream = new FileStream (glue_filename, FileMode.Create, FileAccess.Write); + } catch (Exception) { + Console.Error.WriteLine ("Unable to create specified glue file. Glue will not be generated."); + return; + } + + glue_sw = new StreamWriter (stream); + + glue_sw.WriteLine ("// This file was generated by the Gtk# code generator."); + glue_sw.WriteLine ("// Any changes made will be lost if regenerated."); + glue_sw.WriteLine (); + + if (glue_includes != "") { + foreach (string header in glue_includes.Split (new char[] {',', ' '})) { + if (header != "") + glue_sw.WriteLine ("#include <{0}>", header); + } + glue_sw.WriteLine (""); + } + glue_enabled = true; + } + } + + public string AssemblyName { + get { + return assembly_name; + } + } + + public string CustomDir { + get { + return custom_dir; + } + } + + public string Dir { + get { + return dir; + } + } + + public string GluelibName { + get { + return gluelib_name; + } + } + + public bool GlueEnabled { + get { + return glue_enabled; + } + } + + public StreamWriter GlueWriter { + get { + return glue_sw; + } + } + + public StreamWriter Writer { + get { + return sw; + } + set { + sw = value; + } + } + + public void CloseGlueWriter () + { + if (glue_sw != null) + glue_sw.Close (); + } + + string member; + public string CurrentMember { + get { + return typename + "." + member; + } + set { + member = value; + } + } + + string typename; + public string CurrentType { + get { + return typename; + } + set { + typename = value; + } + } + + public StreamWriter OpenStream (string name) + { + char sep = Path.DirectorySeparatorChar; + if (!Directory.Exists(dir)) + Directory.CreateDirectory(dir); + string filename = dir + sep + name + ".cs"; + + FileStream stream = new FileStream (filename, FileMode.Create, FileAccess.Write); + StreamWriter sw = new StreamWriter (stream); + + sw.WriteLine ("// This file was generated by the Gtk# code generator."); + sw.WriteLine ("// Any changes made will be lost if regenerated."); + sw.WriteLine (); + + return sw; + } + } +} + diff --git a/generator/HandleBase.cs b/generator/HandleBase.cs new file mode 100644 index 0000000000..08f7805a3e --- /dev/null +++ b/generator/HandleBase.cs @@ -0,0 +1,81 @@ +// HandleBase.cs - Base class for Handle types +// +// 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 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 abstract class HandleBase : ClassBase, IAccessor { + + protected HandleBase (XmlElement ns, XmlElement elem) : base (ns, elem) {} + + public override string AssignToName { + get { + return "Raw"; + } + } + + public override string MarshalType { + get { + return "IntPtr"; + } + } + + public override string CallByName (string name) + { + return name + " == null ? IntPtr.Zero : " + name + ".Handle"; + } + + public override string CallByName () + { + return "Handle"; + } + + public abstract string FromNative (string var, bool owned); + + public override string FromNative (string var) + { + return FromNative (var, false); + } + + public string FromNativeReturn (string var, bool owned) + { + return FromNative (var, owned); + } + + public override string FromNativeReturn (string var) + { + return FromNativeReturn (var, false); + } + + public void WriteAccessors (StreamWriter sw, string indent, string var) + { + sw.WriteLine (indent + "get {"); + sw.WriteLine (indent + "\treturn " + FromNative (var, false) + ";"); + sw.WriteLine (indent + "}"); + sw.WriteLine (indent + "set {"); + sw.WriteLine (indent + "\t" + var + " = " + CallByName ("value") + ";"); + sw.WriteLine (indent + "}"); + } + } +} diff --git a/generator/IAccessor.cs b/generator/IAccessor.cs new file mode 100644 index 0000000000..3cfcfc05d5 --- /dev/null +++ b/generator/IAccessor.cs @@ -0,0 +1,29 @@ +// IAccessor.cs - Interface to generate property accessors. +// +// Author: 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 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 { + + public interface IAccessor { + + void WriteAccessors (System.IO.StreamWriter sw, string indentation, string field_name); + + } +} diff --git a/generator/IGeneratable.cs b/generator/IGeneratable.cs new file mode 100644 index 0000000000..1608fd7cd5 --- /dev/null +++ b/generator/IGeneratable.cs @@ -0,0 +1,71 @@ +// GtkSharp.Generation.IGeneratable.cs - Interface to generate code for a type. +// +// Author: Mike Kestner +// +// Copyright (c) 2001 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 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 { + + public interface IGeneratable { + + // The C name of the generatable + string CName {get;} + + // The (short) C# name of the generatable + string Name {get;} + + // The fully-qualified C# name of the generatable + string QualifiedName {get;} + + // The type (possibly including "ref" or "out") to use in the import + // signature when passing this generatable to unmanaged code + string MarshalType {get;} + + // The type to use as the return type in an import signature when + // receiving this generatable back from unmanaged code + string MarshalReturnType {get;} + + // The type to use in a managed callback signature when returning this + // generatable to unmanaged code + string ToNativeReturnType {get;} + + // The value returned by callbacks that are interrupted prematurely + // by managed exceptions or other conditions where an appropriate + // value can't be otherwise obtained. + string DefaultValue {get;} + + // Generates an expression to convert var_name to MarshalType + string CallByName (string var_name); + + // Generates an expression to convert var from MarshalType + string FromNative (string var); + + // Generates an expression to convert var from MarshalReturnType + string FromNativeReturn (string var); + + // Generates an expression to convert var to ToNativeReturnType + string ToNativeReturn (string var); + + bool Validate (); + + void Generate (); + + void Generate (GenerationInfo gen_info); + } +} diff --git a/generator/IManualMarshaler.cs b/generator/IManualMarshaler.cs new file mode 100644 index 0000000000..e9e7eaf3df --- /dev/null +++ b/generator/IManualMarshaler.cs @@ -0,0 +1,32 @@ +// GtkSharp.Generation.IManualMarshaler.cs - Interface for manual marshaling. +// +// Author: 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 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 { + + public interface IManualMarshaler { + + string AllocNative (string managed_var); + + string ReleaseNative (string native_var); + + } +} + diff --git a/generator/InterfaceGen.cs b/generator/InterfaceGen.cs new file mode 100644 index 0000000000..d0dc77b84a --- /dev/null +++ b/generator/InterfaceGen.cs @@ -0,0 +1,351 @@ +// GtkSharp.Generation.InterfaceGen.cs - The Interface Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// Copyright (c) 2004, 2007 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.Collections; + using System.IO; + using System.Xml; + + public class InterfaceGen : ObjectBase { + + bool consume_only; + + public InterfaceGen (XmlElement ns, XmlElement elem) : base (ns, elem, true) + { + consume_only = elem.HasAttribute ("consume_only"); + foreach (XmlNode node in elem.ChildNodes) { + if (!(node is XmlElement)) continue; + XmlElement member = (XmlElement) node; + + switch (member.Name) { + case "signal": + object sig = sigs [member.GetAttribute ("name")]; + if (sig == null) + sig = new Signal (node as XmlElement, this); + break; + default: + if (!base.IsNodeNameHandled (node.Name)) + Console.WriteLine ("Unexpected node " + node.Name + " in " + CName); + break; + } + } + } + + public bool IsConsumeOnly { + get { + return consume_only; + } + } + + public override string FromNative (string var, bool owned) + { + return QualifiedName + "Adapter.GetObject (" + var + ", " + (owned ? "true" : "false") + ")"; + } + + public override bool ValidateForSubclass () + { + ArrayList invalids = new ArrayList (); + + foreach (Method method in methods.Values) { + if (!method.Validate ()) { + Console.WriteLine ("in type " + QualifiedName); + invalids.Add (method); + } + } + foreach (Method method in invalids) + methods.Remove (method.Name); + invalids.Clear (); + + return base.ValidateForSubclass (); + } + + void GenerateStaticCtor (StreamWriter sw) + { + sw.WriteLine ("\t\tstatic {0} iface;", class_struct_name); + sw.WriteLine (); + sw.WriteLine ("\t\tstatic " + Name + "Adapter ()"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tGLib.GType.Register (_gtype, typeof({0}Adapter));", Name); + foreach (InterfaceVM vm in interface_vms) { + if (vm.IsValid) + sw.WriteLine ("\t\t\tiface.{0} = new {0}NativeDelegate ({0}_cb);", vm.Name); + } + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + void GenerateInitialize (StreamWriter sw) + { + sw.WriteLine ("\t\tstatic int class_offset = 2 * IntPtr.Size;"); // Class size of GTypeInterface struct + sw.WriteLine (); + sw.WriteLine ("\t\tstatic void Initialize (IntPtr ptr, IntPtr data)"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tIntPtr ifaceptr = new IntPtr (ptr.ToInt64 () + class_offset);"); + sw.WriteLine ("\t\t\t{0} native_iface = ({0}) Marshal.PtrToStructure (ifaceptr, typeof ({0}));", class_struct_name); + foreach (InterfaceVM vm in interface_vms) + sw.WriteLine ("\t\t\tnative_iface." + vm.Name + " = iface." + vm.Name + ";"); + 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 (InterfaceVM vm in interface_vms) { + vm.GenerateCallback (sw, null); + } + } + + void GenerateCtors (StreamWriter sw) + { + if (!IsConsumeOnly) { + 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 (); + sw.WriteLine ("\t\t{0}Implementor implementor;", Name); + sw.WriteLine (); + sw.WriteLine ("\t\tpublic {0}Adapter ({0}Implementor implementor)", Name); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tif (implementor == null)"); + sw.WriteLine ("\t\t\t\tthrow new ArgumentNullException (\"implementor\");"); + sw.WriteLine ("\t\t\tthis.implementor = implementor;"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + sw.WriteLine ("\t\tpublic " + Name + "Adapter (IntPtr handle)"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tif (!_gtype.IsInstance (handle))"); + sw.WriteLine ("\t\t\t\tthrow new ArgumentException (\"The gobject doesn't implement the GInterface of this adapter\", \"handle\");"); + sw.WriteLine ("\t\t\tthis.handle = handle;"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + void GenerateGType (StreamWriter sw) + { + Method m = GetMethod ("GetType"); + m.GenerateImport (sw); + sw.WriteLine ("\t\tprivate static GLib.GType _gtype = new GLib.GType ({0} ());", m.CName); + sw.WriteLine (); + sw.WriteLine ("\t\tpublic override GLib.GType GType {"); + sw.WriteLine ("\t\t\tget {"); + sw.WriteLine ("\t\t\t\treturn _gtype;"); + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + void GenerateHandleProp (StreamWriter sw) + { + sw.WriteLine ("\t\tIntPtr handle;"); + sw.WriteLine ("\t\tpublic override IntPtr Handle {"); + sw.WriteLine ("\t\t\tget {"); + if (IsConsumeOnly) { + sw.WriteLine ("\t\t\t\treturn handle;"); + } else { + sw.WriteLine ("\t\t\t\tif (handle != IntPtr.Zero)"); + sw.WriteLine ("\t\t\t\t\treturn handle;"); + sw.WriteLine ("\t\t\t\treturn implementor == null ? IntPtr.Zero : implementor.Handle;"); + } + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + void GenerateGetObject (StreamWriter sw) + { + sw.WriteLine ("\t\tpublic static " + Name + " GetObject (IntPtr handle, bool owned)"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tGLib.Object obj = GLib.Object.GetObject (handle, owned);"); + sw.WriteLine ("\t\t\treturn GetObject (obj);"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + sw.WriteLine ("\t\tpublic static " + Name + " GetObject (GLib.Object obj)"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tif (obj == null)"); + sw.WriteLine ("\t\t\t\treturn null;"); + if (!IsConsumeOnly) { + sw.WriteLine ("\t\t\telse if (obj is " + Name + "Implementor)"); + sw.WriteLine ("\t\t\t\treturn new {0}Adapter (obj as {0}Implementor);", Name); + } + sw.WriteLine ("\t\t\telse if (obj as " + Name + " == null)"); + sw.WriteLine ("\t\t\t\treturn new {0}Adapter (obj.Handle);", Name); + sw.WriteLine ("\t\t\telse"); + sw.WriteLine ("\t\t\t\treturn obj as {0};", Name); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + void GenerateImplementorProp (StreamWriter sw) + { + sw.WriteLine ("\t\tpublic " + Name + "Implementor Implementor {"); + sw.WriteLine ("\t\t\tget {"); + sw.WriteLine ("\t\t\t\treturn implementor;"); + 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"); + + sw.WriteLine ("namespace " + NS + " {"); + sw.WriteLine (); + sw.WriteLine ("\tusing System;"); + sw.WriteLine ("\tusing System.Runtime.InteropServices;"); + sw.WriteLine (); + sw.WriteLine ("#region Autogenerated code"); + sw.WriteLine ("\tpublic class " + Name + "Adapter : GLib.GInterfaceAdapter, " + QualifiedName + " {"); + sw.WriteLine (); + + if (!IsConsumeOnly) { + GenerateClassStruct (gen_info); + GenerateStaticCtor (sw); + GenerateCallbacks (sw); + GenerateInitialize (sw); + } + GenerateCtors (sw); + GenerateGType (sw); + GenerateHandleProp (sw); + GenerateGetObject (sw); + if (!IsConsumeOnly) + GenerateImplementorProp (sw); + + GenProperties (gen_info, null); + + foreach (Signal sig in sigs.Values) + sig.GenEvent (sw, null, "GLib.Object.GetObject (Handle)"); + + Method temp = methods ["GetType"] as Method; + if (temp != null) + methods.Remove ("GetType"); + GenMethods (gen_info, new Hashtable (), this); + if (temp != null) + methods ["GetType"] = temp; + + sw.WriteLine ("#endregion"); + + string custom = Path.Combine (gen_info.CustomDir, Name + "Adapter.custom"); + if (File.Exists (custom)) { + sw.WriteLine ("#region Customized extensions"); + sw.WriteLine ("#line 1 \"" + Name + "Adapter.custom\""); + using (StreamReader sr = new StreamReader(new FileStream (custom, FileMode.Open, FileAccess.Read))) + sw.WriteLine (sr.ReadToEnd ()); + + sw.WriteLine ("#endregion"); + } + + sw.WriteLine ("\t}"); + sw.WriteLine ("}"); + sw.Close (); + gen_info.Writer = null; + } + + void GenerateImplementorIface (StreamWriter sw) + { + if (IsConsumeOnly) + return; + + sw.WriteLine (); + sw.WriteLine ("\t[GLib.GInterface (typeof (" + Name + "Adapter))]"); + string access = IsInternal ? "internal" : "public"; + sw.WriteLine ("\t" + access + " interface " + Name + "Implementor : GLib.IWrapper {"); + sw.WriteLine (); + Hashtable vm_table = new Hashtable (); + foreach (InterfaceVM vm in interface_vms) { + vm_table [vm.Name] = vm; + } + foreach (InterfaceVM vm in interface_vms) { + if (vm_table [vm.Name] == null) + continue; + else if (!vm.IsValid) { + vm_table.Remove (vm.Name); + continue; + } else if (vm.IsGetter || vm.IsSetter) { + string cmp_name = (vm.IsGetter ? "Set" : "Get") + vm.Name.Substring (3); + InterfaceVM cmp = vm_table [cmp_name] as InterfaceVM; + if (cmp != null && (cmp.IsGetter || cmp.IsSetter)) { + if (vm.IsSetter) + cmp.GenerateDeclaration (sw, vm); + else + vm.GenerateDeclaration (sw, cmp); + vm_table.Remove (cmp.Name); + } else + vm.GenerateDeclaration (sw, null); + vm_table.Remove (vm.Name); + } else { + vm.GenerateDeclaration (sw, null); + vm_table.Remove (vm.Name); + } + } + sw.WriteLine ("\t}"); + } + + public override void Generate (GenerationInfo gen_info) + { + GenerateAdapter (gen_info); + StreamWriter sw = gen_info.Writer = gen_info.OpenStream (Name); + + sw.WriteLine ("namespace " + NS + " {"); + sw.WriteLine (); + sw.WriteLine ("\tusing System;"); + sw.WriteLine (); + sw.WriteLine ("#region Autogenerated code"); + string access = IsInternal ? "internal" : "public"; + sw.WriteLine ("\t" + access + " interface " + Name + " : GLib.IWrapper {"); + sw.WriteLine (); + + foreach (Signal sig in sigs.Values) { + sig.GenerateDecl (sw); + sig.GenEventHandler (gen_info); + } + + foreach (Method method in methods.Values) { + if (IgnoreMethod (method, this)) + continue; + method.GenerateDecl (sw); + } + + foreach (Property prop in props.Values) + prop.GenerateDecl (sw, "\t\t"); + + AppendCustom (sw, gen_info.CustomDir); + + sw.WriteLine ("\t}"); + GenerateImplementorIface (sw); + sw.WriteLine ("#endregion"); + sw.WriteLine ("}"); + sw.Close (); + gen_info.Writer = null; + Statistics.IFaceCount++; + } + } +} + diff --git a/generator/InterfaceVM.cs b/generator/InterfaceVM.cs new file mode 100644 index 0000000000..205baab393 --- /dev/null +++ b/generator/InterfaceVM.cs @@ -0,0 +1,97 @@ + +// GtkSharp.Generation.InterfaceVM.cs - interface-specific part of VM creation +// +// Author: Christian Hoff +// +// Copyright (c) 2009 Christian Hoff +// +// 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.Collections; + using System.IO; + using System.Xml; + + public class InterfaceVM : VirtualMethod + { + private Method target; + + public InterfaceVM (XmlElement elem, Method target, ObjectBase container_type) : base (elem, container_type) + { + this.target = target; + parms.HideData = true; + this.Protection = "public"; + } + + public bool IsGetter { + get { + return HasGetterName && ((!retval.IsVoid && parms.Count == 0) || (retval.IsVoid && parms.Count == 1 && parms [0].PassAs == "out")); + } + } + + public bool IsSetter { + get { + if (!HasSetterName || !retval.IsVoid) + return false; + + if (parms.Count == 1 || (parms.Count == 3 && parms [0].Scope == "notified")) + return true; + else + return false; + } + } + + protected override string CallString { + get { + if (IsGetter) + return (target.Name.StartsWith ("Get") ? target.Name.Substring (3) : target.Name); + else if (IsSetter) + return target.Name.Substring (3) + " = " + call; + else + return target.Name + " (" + call + ")"; + } + } + + public void GenerateDeclaration (StreamWriter sw, InterfaceVM complement) + { + if (IsGetter) { + string name = Name.StartsWith ("Get") ? Name.Substring (3) : Name; + string type = retval.IsVoid ? parms [0].CSType : retval.CSType; + if (complement != null && complement.parms [0].CSType == type) + sw.WriteLine ("\t\t" + type + " " + name + " { get; set; }"); + else { + sw.WriteLine ("\t\t" + type + " " + name + " { get; }"); + if (complement != null) + sw.WriteLine ("\t\t" + complement.retval.CSType + " " + complement.Name + " (" + complement.Signature + ");"); + } + } else if (IsSetter) + sw.WriteLine ("\t\t" + parms[0].CSType + " " + Name.Substring (3) + " { set; }"); + else + sw.WriteLine ("\t\t" + retval.CSType + " " + Name + " (" + Signature + ");"); + } + + public override bool Validate () + { + if (target == null) { + Console.WriteLine ("Virtual method {0}->{1} has no matching target to invoke", container_type.CName, CName); + return false; + } + return base.Validate (); + } + } +} diff --git a/generator/LPGen.cs b/generator/LPGen.cs new file mode 100644 index 0000000000..3fb774ec6c --- /dev/null +++ b/generator/LPGen.cs @@ -0,0 +1,58 @@ +// GtkSharp.Generation.LPGen.cs - long/pointer Generatable. +// +// Author: 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; + + public class LPGen : SimpleGen, IAccessor { + + public LPGen (string ctype) : base (ctype, "long", "0L") {} + + public override string MarshalType { + get { + return "IntPtr"; + } + } + + public override string CallByName (string var_name) + { + return "new IntPtr (" + var_name + ")"; + } + + public override string FromNative(string var) + { + return "(long) " + var; + } + + public void WriteAccessors (StreamWriter sw, string indent, string var) + { + sw.WriteLine (indent + "get {"); + sw.WriteLine (indent + "\treturn " + FromNative (var) + ";"); + sw.WriteLine (indent + "}"); + sw.WriteLine (indent + "set {"); + sw.WriteLine (indent + "\t" + var + " = " + CallByName ("value") + ";"); + sw.WriteLine (indent + "}"); + } + } +} + diff --git a/generator/LPUGen.cs b/generator/LPUGen.cs new file mode 100644 index 0000000000..331b25f983 --- /dev/null +++ b/generator/LPUGen.cs @@ -0,0 +1,58 @@ +// GtkSharp.Generation.LPUGen.cs - unsugned long/pointer generatable. +// +// Author: 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; + + public class LPUGen : SimpleGen, IAccessor { + + public LPUGen (string ctype) : base (ctype, "ulong", "0") {} + + public override string MarshalType { + get { + return "UIntPtr"; + } + } + + public override string CallByName (string var_name) + { + return "new UIntPtr (" + var_name + ")"; + } + + public override string FromNative(string var) + { + return "(ulong) " + var; + } + + public void WriteAccessors (StreamWriter sw, string indent, string var) + { + sw.WriteLine (indent + "get {"); + sw.WriteLine (indent + "\treturn " + FromNative (var) + ";"); + sw.WriteLine (indent + "}"); + sw.WriteLine (indent + "set {"); + sw.WriteLine (indent + "\t" + var + " = " + CallByName ("value") + ";"); + sw.WriteLine (indent + "}"); + } + } +} + diff --git a/generator/Makefile.am b/generator/Makefile.am new file mode 100644 index 0000000000..62cbd297c8 --- /dev/null +++ b/generator/Makefile.am @@ -0,0 +1,67 @@ +noinst_SCRIPTS = gst-gapi_codegen.exe + +references = + +sources = \ + AliasGen.cs \ + BoxedGen.cs \ + ByRefGen.cs \ + CallbackGen.cs \ + ChildProperty.cs \ + ClassBase.cs \ + ClassField.cs \ + ClassGen.cs \ + CodeGenerator.cs \ + ConstFilenameGen.cs \ + ConstStringGen.cs \ + Ctor.cs \ + DefaultSignalHandler.cs \ + EnumGen.cs \ + FieldBase.cs \ + GenBase.cs \ + GenerationInfo.cs \ + GObjectVM.cs \ + HandleBase.cs \ + IAccessor.cs \ + IGeneratable.cs \ + IManualMarshaler.cs \ + InterfaceGen.cs \ + InterfaceVM.cs \ + LPGen.cs \ + LPUGen.cs \ + ManagedCallString.cs \ + ManualGen.cs \ + MarshalGen.cs \ + MethodBase.cs \ + MethodBody.cs \ + Method.cs \ + ObjectField.cs \ + ObjectBase.cs \ + ObjectGen.cs \ + OpaqueGen.cs \ + Parameters.cs \ + Parser.cs \ + Property.cs \ + PropertyBase.cs \ + ReturnValue.cs \ + Signal.cs \ + Signature.cs \ + SimpleBase.cs \ + SimpleGen.cs \ + Statistics.cs \ + StructBase.cs \ + StructField.cs \ + StructGen.cs \ + SymbolTable.cs \ + VirtualMethod.cs \ + VMSignature.cs + +build_sources = $(addprefix $(srcdir)/, $(sources)) +dist_sources = $(sources) + +EXTRA_DIST = \ + $(dist_sources) + +gst-gapi_codegen.exe: $(build_sources) + $(CSC) /debug /out:gst-gapi_codegen.exe $(OFF_T_FLAGS) $(references) $(build_sources) + diff --git a/generator/ManagedCallString.cs b/generator/ManagedCallString.cs new file mode 100644 index 0000000000..766f636f9f --- /dev/null +++ b/generator/ManagedCallString.cs @@ -0,0 +1,152 @@ +// GtkSharp.Generation.ManagedCallString.cs - The ManagedCallString Class. +// +// Author: Mike Kestner +// +// Copyright (c) 2003 Mike Kestner +// +// 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.Collections; + using System.IO; + + public class ManagedCallString { + + ArrayList parms = new ArrayList (); + ArrayList special = new ArrayList (); + string error_param = null; + string user_data_param = null; + string destroy_param = null; + + public ManagedCallString (Parameters parms) + { + for (int i = 0; i < parms.Count; i ++) { + Parameter p = parms [i]; + if (p.IsLength && i > 0 && parms [i-1].IsString) + continue; + else if (p.Scope == "notified") { + user_data_param = parms[i+1].Name; + destroy_param = parms[i+2].Name; + i += 2; + } else if (p.IsUserData && parms.IsHidden (p)) { + user_data_param = p.Name; + continue; + } else if (p is ErrorParameter) { + error_param = p.Name; + continue; + } + this.parms.Add (p); + + 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); + } + } + + public bool HasOutParam { + get { + foreach (Parameter p in parms) { + if (p.PassAs == "out") + return true; + } + return false; + } + } + + public string Unconditional (string indent) { + string ret = ""; + if (error_param != null) + ret = indent + error_param + " = IntPtr.Zero;\n"; + return ret; + } + + public string Setup (string indent) + { + string ret = ""; + + for (int i = 0; i < parms.Count; i ++) { + if ((bool)special[i] == false) + continue; + + Parameter p = parms [i] as Parameter; + IGeneratable igen = p.Generatable; + + if (igen is CallbackGen) { + if (user_data_param == null) + ret += indent + String.Format ("{0} {1}_invoker = new {0} ({1});\n", (igen as CallbackGen).InvokerName, p.Name); + else if (destroy_param == null) + ret += indent + String.Format ("{0} {1}_invoker = new {0} ({1}, {2});\n", (igen as CallbackGen).InvokerName, p.Name, user_data_param); + else + ret += indent + String.Format ("{0} {1}_invoker = new {0} ({1}, {2}, {3});\n", (igen as CallbackGen).InvokerName, p.Name, user_data_param, destroy_param); + } else { + ret += indent + igen.QualifiedName + " my" + p.Name; + if (p.PassAs == "ref") + ret += " = " + p.FromNative (p.Name); + ret += ";\n"; + } + } + + return ret; + } + + public override string ToString () + { + if (parms.Count < 1) + return ""; + + string[] result = new string [parms.Count]; + + for (int i = 0; i < parms.Count; i ++) { + Parameter p = parms [i] as Parameter; + result [i] = p.PassAs == "" ? "" : p.PassAs + " "; + 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); + } + + public string Finish (string indent) + { + string ret = ""; + + for (int i = 0; i < parms.Count; i ++) { + if ((bool)special[i] == false) + continue; + + Parameter p = parms [i] as Parameter; + IGeneratable igen = p.Generatable; + + 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"; + } + + return ret; + } + } +} + diff --git a/generator/ManualGen.cs b/generator/ManualGen.cs new file mode 100644 index 0000000000..1d94916bb7 --- /dev/null +++ b/generator/ManualGen.cs @@ -0,0 +1,58 @@ +// GtkSharp.Generation.ManualGen.cs - Ungenerated handle type Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 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; + + public class ManualGen : SimpleBase { + + string from_fmt; + + public ManualGen (string ctype, string type) : base (ctype, type, "null") + { + from_fmt = "new " + QualifiedName + "({0})"; + } + + public ManualGen (string ctype, string type, string from_fmt) : base (ctype, type, "null") + { + this.from_fmt = from_fmt; + } + + public override string MarshalType { + get { + return "IntPtr"; + } + } + + public override string CallByName (string var_name) + { + return var_name + " == null ? IntPtr.Zero : " + var_name + ".Handle"; + } + + public override string FromNative(string var) + { + return String.Format (from_fmt, var); + } + } +} + diff --git a/generator/MarshalGen.cs b/generator/MarshalGen.cs new file mode 100644 index 0000000000..b81a487a44 --- /dev/null +++ b/generator/MarshalGen.cs @@ -0,0 +1,58 @@ +// GtkSharp.Generation.MarshalGen.cs - Simple marshaling Generatable. +// +// Author: 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; + + public class MarshalGen : SimpleBase { + + string mtype; + string call_fmt; + string from_fmt; + + public MarshalGen (string ctype, string type, string mtype, string call_fmt, string from_fmt, string default_value) : base (ctype, type, default_value) + { + this.mtype = mtype; + this.call_fmt = call_fmt; + this.from_fmt = from_fmt; + } + + public MarshalGen (string ctype, string type, string mtype, string call_fmt, string from_fmt) : this (ctype, type, mtype, call_fmt, from_fmt, "null") { } + + public override string MarshalType { + get { + return mtype; + } + } + + public override string CallByName (string var) + { + return String.Format (call_fmt, var); + } + + public override string FromNative (string var) + { + return String.Format (from_fmt, var); + } + } +} + diff --git a/generator/Method.cs b/generator/Method.cs new file mode 100644 index 0000000000..1492bc4639 --- /dev/null +++ b/generator/Method.cs @@ -0,0 +1,304 @@ +// GtkSharp.Generation.Method.cs - The Method Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// Copyright (c) 2003-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.Collections; + using System.IO; + using System.Xml; + + public class Method : MethodBase { + + private ReturnValue retval; + + private string call; + private bool is_get, is_set; + private bool deprecated = false; + + public Method (XmlElement elem, ClassBase container_type) : base (elem, container_type) + { + this.retval = new ReturnValue (elem["return-type"]); + + if (!container_type.IsDeprecated && elem.HasAttribute ("deprecated")) { + string attr = elem.GetAttribute ("deprecated"); + deprecated = attr == "1" || attr == "true"; + } + + if (Name == "GetType") + Name = "GetGType"; + } + + public bool IsDeprecated { + get { + return deprecated; + } + } + + public bool IsGetter { + get { + return is_get; + } + } + + public bool IsSetter { + get { + return is_set; + } + } + + public string ReturnType { + get { + return retval.CSType; + } + } + + public override bool Validate () + { + if (!retval.Validate () || !base.Validate ()) { + Console.Write(" in method " + Name + " "); + return false; + } + + Parameters parms = Parameters; + is_get = ((((parms.IsAccessor && retval.IsVoid) || (parms.Count == 0 && !retval.IsVoid)) || (parms.Count == 0 && !retval.IsVoid)) && HasGetterName); + is_set = ((parms.IsAccessor || (parms.VisibleCount == 1 && retval.IsVoid)) && HasSetterName); + + call = "(" + (IsStatic ? "" : container_type.CallByName () + (parms.Count > 0 ? ", " : "")) + Body.GetCallString (is_set) + ")"; + + return true; + } + + private Method GetComplement () + { + char complement; + if (is_get) + complement = 'S'; + else + complement = 'G'; + + return container_type.GetMethod (complement + BaseName.Substring (1)); + } + + public string Declaration { + get { + return retval.CSType + " " + Name + " (" + (Signature != null ? Signature.ToString() : "") + ");"; + } + } + + private void GenerateDeclCommon (StreamWriter sw, ClassBase implementor) + { + if (IsStatic) + sw.Write("static "); + sw.Write (Safety); + Method dup = null; + if (container_type != null) + dup = container_type.GetMethodRecursively (Name); + if (implementor != null) + dup = implementor.GetMethodRecursively (Name); + + if (Name == "ToString" && Parameters.Count == 0) + sw.Write("override "); + else if (Name == "GetGType" && container_type is ObjectGen) + sw.Write("new "); + else if (Modifiers == "new " || (dup != null && ((dup.Signature != null && Signature != null && dup.Signature.ToString() == Signature.ToString()) || (dup.Signature == null && Signature == null)))) + sw.Write("new "); + + if (is_get || is_set) { + if (retval.IsVoid) + sw.Write (Parameters.AccessorReturnType); + else + sw.Write(retval.CSType); + sw.Write(" "); + if (Name.StartsWith ("Get") || Name.StartsWith ("Set")) + sw.Write (Name.Substring (3)); + else { + int dot = Name.LastIndexOf ('.'); + if (dot != -1 && (Name.Substring (dot + 1, 3) == "Get" || Name.Substring (dot + 1, 3) == "Set")) + sw.Write (Name.Substring (0, dot + 1) + Name.Substring (dot + 4)); + else + sw.Write (Name); + } + sw.WriteLine(" { "); + } else if (IsAccessor) { + sw.Write (Signature.AccessorType + " " + Name + "(" + Signature.AsAccessor + ")"); + } else { + sw.Write(retval.CSType + " " + Name + "(" + (Signature != null ? Signature.ToString() : "") + ")"); + } + } + + public void GenerateDecl (StreamWriter sw) + { + if (IsStatic) + return; + + if (is_get || is_set) + { + Method comp = GetComplement (); + if (comp != null && is_set) + return; + + sw.Write("\t\t"); + GenerateDeclCommon (sw, null); + + sw.Write("\t\t\t"); + sw.Write ((is_get) ? "get;" : "set;"); + + if (comp != null && comp.is_set) + sw.WriteLine (" set;"); + else + sw.WriteLine (); + + sw.WriteLine ("\t\t}"); + } + else + { + sw.Write("\t\t"); + GenerateDeclCommon (sw, null); + sw.WriteLine (";"); + } + + Statistics.MethodCount++; + } + + public void GenerateImport (StreamWriter sw) + { + string import_sig = IsStatic ? "" : container_type.MarshalType + " raw"; + import_sig += !IsStatic && Parameters.Count > 0 ? ", " : ""; + import_sig += Parameters.ImportSignature.ToString(); + sw.WriteLine("\t\t[DllImport(\"" + LibraryName + "\")]"); + if (retval.MarshalType.StartsWith ("[return:")) + sw.WriteLine("\t\t" + retval.MarshalType + " static extern " + Safety + retval.CSType + " " + CName + "(" + import_sig + ");"); + else + sw.WriteLine("\t\tstatic extern " + Safety + retval.MarshalType + " " + CName + "(" + import_sig + ");"); + sw.WriteLine(); + } + + public void Generate (GenerationInfo gen_info, ClassBase implementor) + { + if (!Validate ()) + return; + + Method comp = null; + + gen_info.CurrentMember = Name; + + /* we are generated by the get Method, if there is one */ + if (is_set || is_get) + { + if (Modifiers != "new " && container_type.GetPropertyRecursively (Name.Substring (3)) != null) + return; + comp = GetComplement (); + if (comp != null && is_set) { + if (Parameters.AccessorReturnType == comp.ReturnType) + return; + else { + is_set = false; + call = "(Handle, " + Body.GetCallString (false) + ")"; + comp = null; + } + } + /* some setters take more than one arg */ + if (comp != null && !comp.is_set) + comp = null; + } + + GenerateImport (gen_info.Writer); + if (comp != null && retval.CSType == comp.Parameters.AccessorReturnType) + comp.GenerateImport (gen_info.Writer); + + if (IsDeprecated) + gen_info.Writer.WriteLine("\t\t[Obsolete]"); + gen_info.Writer.Write("\t\t"); + if (Protection != "") + gen_info.Writer.Write("{0} ", Protection); + GenerateDeclCommon (gen_info.Writer, implementor); + + if (is_get || is_set) + { + gen_info.Writer.Write ("\t\t\t"); + gen_info.Writer.Write ((is_get) ? "get" : "set"); + GenerateBody (gen_info, implementor, "\t"); + } + else + GenerateBody (gen_info, implementor, ""); + + if (is_get || is_set) + { + if (comp != null && retval.CSType == comp.Parameters.AccessorReturnType) + { + gen_info.Writer.WriteLine (); + gen_info.Writer.Write ("\t\t\tset"); + comp.GenerateBody (gen_info, implementor, "\t"); + } + gen_info.Writer.WriteLine (); + gen_info.Writer.WriteLine ("\t\t}"); + } + else + gen_info.Writer.WriteLine(); + + gen_info.Writer.WriteLine(); + + Statistics.MethodCount++; + } + + public void GenerateBody (GenerationInfo gen_info, ClassBase implementor, string indent) + { + StreamWriter sw = gen_info.Writer; + sw.WriteLine(" {"); + if (!IsStatic && implementor != null) + implementor.Prepare (sw, indent + "\t\t\t"); + if (IsAccessor) + Body.InitAccessor (sw, Signature, indent); + Body.Initialize(gen_info, is_get, is_set, indent); + + sw.Write(indent + "\t\t\t"); + if (retval.IsVoid) + sw.WriteLine(CName + call + ";"); + else { + sw.WriteLine(retval.MarshalType + " raw_ret = " + CName + call + ";"); + sw.WriteLine(indent + "\t\t\t" + retval.CSType + " ret = " + retval.FromNative ("raw_ret") + ";"); + } + + if (!IsStatic && implementor != null) + implementor.Finish (sw, indent + "\t\t\t"); + Body.Finish (sw, indent); + Body.HandleException (sw, indent); + + if (is_get && Parameters.Count > 0) + sw.WriteLine (indent + "\t\t\treturn " + Parameters.AccessorName + ";"); + else if (!retval.IsVoid) + sw.WriteLine (indent + "\t\t\treturn ret;"); + else if (IsAccessor) + Body.FinishAccessor (sw, Signature, indent); + + sw.Write(indent + "\t\t}"); + } + + bool IsAccessor { + get { + return retval.IsVoid && Signature.IsAccessor; + } + } + } +} + diff --git a/generator/MethodBase.cs b/generator/MethodBase.cs new file mode 100644 index 0000000000..2faaef156b --- /dev/null +++ b/generator/MethodBase.cs @@ -0,0 +1,183 @@ +// GtkSharp.Generation.MethodBase.cs - function element base class. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// Copyright (c) 2004-2005 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.Xml; + + public abstract class MethodBase { + + protected XmlElement elem; + protected ClassBase container_type; + protected Parameters parms; + string mods = String.Empty; + string name; + private string protection = "public"; + + protected MethodBase (XmlElement elem, ClassBase container_type) + { + this.elem = elem; + this.container_type = container_type; + this.name = elem.GetAttribute ("name"); + parms = new Parameters (elem ["parameters"]); + IsStatic = elem.GetAttribute ("shared") == "true"; + if (elem.HasAttribute ("new_flag")) + mods = "new "; + if (elem.HasAttribute ("accessibility")) { + string attr = elem.GetAttribute ("accessibility"); + switch (attr) { + case "public": + case "protected": + case "internal": + case "private": + case "protected internal": + protection = attr; + break; + } + } + } + + protected string BaseName { + get { + string name = Name; + int idx = Name.LastIndexOf ("."); + if (idx > 0) + name = Name.Substring (idx + 1); + return name; + } + } + + MethodBody body; + public MethodBody Body { + get { + if (body == null) + body = new MethodBody (parms); + return body; + } + } + + public virtual string CName { + get { + return SymbolTable.Table.MangleName (elem.GetAttribute ("cname")); + } + } + + protected bool HasGetterName { + get { + string name = BaseName; + if (name.Length <= 3) + return false; + if (name.StartsWith ("Get") || name.StartsWith ("Has")) + return Char.IsUpper (name [3]); + else if (name.StartsWith ("Is")) + return Char.IsUpper (name [2]); + else + return false; + } + } + + protected bool HasSetterName { + get { + string name = BaseName; + if (name.Length <= 3) + return false; + + return name.StartsWith ("Set") && Char.IsUpper (name [3]); + } + } + + public bool IsStatic { + get { + return parms.Static; + } + set { + parms.Static = value; + } + } + + public string LibraryName { + get { + if (elem.HasAttribute ("library")) + return elem.GetAttribute ("library"); + return container_type.LibraryName; + } + } + + public string Modifiers { + get { + return mods; + } + set { + mods = value; + } + } + + public string Name { + get { + return name; + } + set { + name = value; + } + } + + public Parameters Parameters { + get { + return parms; + } + } + + + public string Protection { + get { return protection; } + set { protection = value; } + } + + protected string Safety { + get { + return Body.ThrowsException && !(container_type is InterfaceGen) ? "unsafe " : ""; + } + } + + Signature sig; + public Signature Signature { + get { + if (sig == null) + sig = new Signature (parms); + return sig; + } + } + + public virtual bool Validate () + { + if (!parms.Validate ()) { + Console.Write("in " + CName + " "); + Statistics.ThrottledCount++; + return false; + } + + return true; + } + } +} + diff --git a/generator/MethodBody.cs b/generator/MethodBody.cs new file mode 100644 index 0000000000..cee70790f1 --- /dev/null +++ b/generator/MethodBody.cs @@ -0,0 +1,177 @@ +// GtkSharp.Generation.MethodBody.cs - The MethodBody Generation Class. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// Copyright (c) 2003-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.Collections; + using System.IO; + + public class MethodBody { + + Parameters parameters; + + public MethodBody (Parameters parms) + { + parameters = parms; + } + + private string CastFromInt (string type) + { + return type != "int" ? "(" + type + ") " : ""; + } + + public string GetCallString (bool is_set) + { + if (parameters.Count == 0) + return String.Empty; + + string[] result = new string [parameters.Count]; + for (int i = 0; i < parameters.Count; i++) { + Parameter p = parameters [i]; + IGeneratable igen = p.Generatable; + + bool is_prop = is_set && i == 0; + + if (i > 0 && parameters [i - 1].IsString && p.IsLength && p.PassAs == String.Empty) { + string string_name = (i == 1 && is_set) ? "value" : parameters [i - 1].Name; + result[i] = igen.CallByName (CastFromInt (p.CSType) + "System.Text.Encoding.UTF8.GetByteCount (" + string_name + ")"); + continue; + } + + if (is_prop) + p.CallName = "value"; + else + p.CallName = p.Name; + string call_parm = p.CallString; + + if (p.IsUserData && parameters.IsHidden (p) && !parameters.HideData && + (i == 0 || parameters [i - 1].Scope != "notified")) { + call_parm = "IntPtr.Zero"; + } + + result [i] += call_parm; + } + + 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) + return; + + StreamWriter sw = gen_info.Writer; + for (int i = 0; i < parameters.Count; i++) { + Parameter p = parameters [i]; + + IGeneratable gen = p.Generatable; + string name = p.Name; + if (is_set) + name = "value"; + + p.CallName = name; + foreach (string prep in p.Prepare) + sw.WriteLine (indent + "\t\t\t" + prep); + + if (gen is CallbackGen) { + CallbackGen cbgen = gen as CallbackGen; + string wrapper = cbgen.GenWrapper(gen_info); + switch (p.Scope) { + case "notified": + sw.WriteLine (indent + "\t\t\t{0} {1}_wrapper = new {0} ({1});", wrapper, name); + sw.WriteLine (indent + "\t\t\tIntPtr {0};", parameters [i + 1].Name); + sw.WriteLine (indent + "\t\t\t{0} {1};", parameters [i + 2].CSType, parameters [i + 2].Name); + sw.WriteLine (indent + "\t\t\tif ({0} == null) {{", name); + sw.WriteLine (indent + "\t\t\t\t{0} = IntPtr.Zero;", parameters [i + 1].Name); + sw.WriteLine (indent + "\t\t\t\t{0} = null;", parameters [i + 2].Name); + sw.WriteLine (indent + "\t\t\t} else {"); + sw.WriteLine (indent + "\t\t\t\t{0} = (IntPtr) GCHandle.Alloc ({1}_wrapper);", parameters [i + 1].Name, name); + sw.WriteLine (indent + "\t\t\t\t{0} = GLib.DestroyHelper.NotifyHandler;", parameters [i + 2].Name, parameters [i + 2].CSType); + sw.WriteLine (indent + "\t\t\t}"); + break; + + case "async": + sw.WriteLine (indent + "\t\t\t{0} {1}_wrapper = new {0} ({1});", wrapper, name); + sw.WriteLine (indent + "\t\t\t{0}_wrapper.PersistUntilCalled ();", name); + break; + case "call": + default: + if (p.Scope == String.Empty) + Console.WriteLine ("Defaulting " + gen.Name + " param to 'call' scope in method " + gen_info.CurrentMember); + sw.WriteLine (indent + "\t\t\t{0} {1}_wrapper = new {0} ({1});", wrapper, name); + break; + } + } + } + + if (ThrowsException) + sw.WriteLine (indent + "\t\t\tIntPtr error = IntPtr.Zero;"); + } + + public void InitAccessor (StreamWriter sw, Signature sig, string indent) + { + sw.WriteLine (indent + "\t\t\t" + sig.AccessorType + " " + sig.AccessorName + ";"); + } + + public void Finish (StreamWriter sw, string indent) + { + foreach (Parameter p in parameters) + foreach (string s in p.Finish) + sw.WriteLine(indent + "\t\t\t" + s); + } + + public void FinishAccessor (StreamWriter sw, Signature sig, string indent) + { + sw.WriteLine (indent + "\t\t\treturn " + sig.AccessorName + ";"); + } + + public void HandleException (StreamWriter sw, string indent) + { + if (!ThrowsException) + return; + sw.WriteLine (indent + "\t\t\tif (error != IntPtr.Zero) throw new GLib.GException (error);"); + } + + public bool ThrowsException { + get { + int idx = parameters.Count - 1; + + while (idx >= 0) { + if (parameters [idx].IsUserData) + idx--; + else if (parameters [idx].CType == "GError**") + return true; + else + break; + } + return false; + } + } + } +} + diff --git a/generator/ObjectBase.cs b/generator/ObjectBase.cs new file mode 100644 index 0000000000..7c5149ebed --- /dev/null +++ b/generator/ObjectBase.cs @@ -0,0 +1,315 @@ +// ObjectBase.cs - Base class for Object types +// +// Authors: Mike Kestner +// +// Copyright (c) 2005 Novell, Inc. +// Copyright (c) 2009 Christian Hoff +// +// 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.Collections; + using System.IO; + using System.Xml; + + public abstract class ObjectBase : HandleBase { + bool is_interface; + protected string class_struct_name = null; + bool class_fields_valid; // false if the class structure contains a bitfield or fields of unknown types + ArrayList class_members = new ArrayList (); + protected ArrayList class_fields = new ArrayList (); + // The default handlers of these signals need to be overridden with g_signal_override_class_closure + protected ArrayList virtual_methods = new ArrayList (); + // virtual methods that are generated as an IntPtr in the class struct + protected ArrayList hidden_vms = new ArrayList (); + protected ArrayList interface_vms = new ArrayList (); + protected Hashtable sigs = new Hashtable(); + + protected ObjectBase (XmlElement ns, XmlElement elem, bool is_interface) : base (ns, elem) + { + this.is_interface = is_interface; + XmlElement class_elem = null; + Hashtable vms = new Hashtable (); + Hashtable signal_vms = new Hashtable (); + + if (this.ParserVersion == 1) + class_struct_name = this.CName + (is_interface ? "Iface" : "Class"); + + foreach (XmlNode node in elem.ChildNodes) { + if (!(node is XmlElement)) continue; + XmlElement member = node as XmlElement; + + switch (node.Name) { + case "virtual_method": + if (this.ParserVersion == 1) { + if (is_interface) // Generating non-signal GObject virtual methods is not supported in compatibility mode + AddVM (member, false, is_interface); + } else + vms.Add (member.GetAttribute ("cname"), member); + break; + + case "signal": + if (this.ParserVersion == 1 || member.GetAttribute ("field_name") == "") + AddVM (member, true, is_interface); + else + signal_vms.Add (member.GetAttribute ("field_name"), member); + + if (member.GetAttribute ("hidden") != "1") { + string name = member.GetAttribute("name"); + while (sigs.ContainsKey(name)) + name += "mangled"; + sigs.Add (name, new Signal (member, this)); + } + break; + + case "class_struct": + class_elem = member; + break; + } + } + + if (class_elem == null) return; + class_struct_name = class_elem.GetAttribute ("cname"); + + for (int node_idx = 0; node_idx < class_elem.ChildNodes.Count; node_idx++) { + XmlNode node = class_elem.ChildNodes [node_idx]; + if (!(node is XmlElement)) continue; + XmlElement member = (XmlElement) node; + + switch (member.Name) { + case "method": + string vm_name; + XmlElement vm_elem; + bool is_signal_vm = member.HasAttribute ("signal_vm"); + if (is_signal_vm) { + vm_name = member.GetAttribute ("signal_vm"); + vm_elem = signal_vms [vm_name] as XmlElement; + } else { + vm_name = member.GetAttribute ("vm"); + vm_elem = vms [vm_name] as XmlElement; + } + + AddVM (vm_elem, is_signal_vm, is_interface); + break; + case "field": + if (node_idx == 0) continue; // Parent class + ClassField field = new ClassField (member, this); + class_fields.Add (field); + class_members.Add (field); + break; + default: + Console.WriteLine ("Unexpected node " + member.Name + " in " + class_elem.GetAttribute ("cname")); + break; + } + } + } + + VirtualMethod AddVM (XmlElement vm_elem, bool is_signal_vm, bool is_interface) + { + VirtualMethod vm; + if (is_signal_vm) + vm = new DefaultSignalHandler (vm_elem, this); + else if (is_interface) + vm = new InterfaceVM (vm_elem, methods [vm_elem.GetAttribute ("name")] as Method, this); + else + vm = new GObjectVM (vm_elem, this); + + if (vm_elem.GetAttribute ("padding") == "true" || vm_elem.GetAttribute ("hidden") == "1") + hidden_vms.Add (vm); + else { + if (vm is GObjectVM) + virtual_methods.Add (vm); + else + interface_vms.Add (vm); + } + if (vm.CName != "") + class_members.Add (vm); + + return vm; + } + + protected override bool IsNodeNameHandled (string name) + { + switch (name) { + case "virtual_method": + case "signal": + case "class_struct": + return true; + default: + return base.IsNodeNameHandled (name); + } + } + + public override string FromNative (string var, bool owned) + { + return "GLib.Object.GetObject(" + var + (owned ? ", true" : "") + ") as " + QualifiedName; + } + + public string ClassStructName { + get { + return class_struct_name; + } + } + + public bool CanGenerateClassStruct { + get { + /* Generation of interface class structs was already supported by version 2.12 of the GAPI parser. Their layout was determined by the order + * in which the signal and virtual_method elements appeared in the XML. However, we cannot use that approach for old GObject class structs + * as they may contain class fields which don't appear in the old (version 1) API files. There are also cases in which the order of the + * and elements do not match the struct layout. + */ + return (is_interface || this.ParserVersion >= 2) && class_fields_valid; + } + } + + protected void GenerateClassStruct (GenerationInfo gen_info) + { + if (class_struct_name == null || !CanGenerateClassStruct) return; + + StreamWriter sw = gen_info.Writer; + + sw.WriteLine ("\t\t[StructLayout (LayoutKind.Sequential)]"); + sw.WriteLine ("\t\tstruct " + class_struct_name + " {"); + foreach (object member in class_members) { + if (member is VirtualMethod) { + VirtualMethod vm = member as VirtualMethod; + if (hidden_vms.Contains (vm) || (is_interface && vm is DefaultSignalHandler)) + sw.WriteLine ("\t\t\tIntPtr {0};", vm.Name); + else + sw.WriteLine ("\t\t\tpublic {0}NativeDelegate {0};", vm.Name); + } else if (member is ClassField) { + ClassField field = member as ClassField; + field.Generate (gen_info, "\t\t\t"); + } + } + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + public Hashtable Signals { + get { + return sigs; + } + } + + public Signal GetSignal (string name) + { + return sigs[name] as Signal; + } + + public Signal GetSignalRecursively (string name) + { + return GetSignalRecursively (name, false); + } + + public virtual Signal GetSignalRecursively (string name, bool check_self) + { + Signal p = null; + if (check_self) + p = GetSignal (name); + if (p == null && Parent != null) + p = (Parent as ObjectBase).GetSignalRecursively (name, true); + + if (check_self && p == null) { + foreach (string iface in interfaces) { + InterfaceGen igen = SymbolTable.Table.GetClassGen (iface) as InterfaceGen; + if (igen == null) + continue; + p = igen.GetSignalRecursively (name, true); + if (p != null) + break; + } + } + + return p; + } + + public void GenSignals (GenerationInfo gen_info, ObjectBase implementor) + { + foreach (Signal sig in sigs.Values) + sig.Generate (gen_info, implementor); + } + + public void GenVirtualMethods (GenerationInfo gen_info, ObjectBase implementor) + { + foreach (GObjectVM vm in virtual_methods) + vm.Generate (gen_info, implementor); + } + + public override bool Validate () + { + if (Parent != null && !(Parent as ObjectBase).ValidateForSubclass ()) + return false; + + ArrayList invalids = new ArrayList (); + + foreach (GObjectVM vm in virtual_methods) + if (!vm.Validate ()) + invalids.Add (vm); + + foreach (VirtualMethod invalid_vm in invalids) { + virtual_methods.Remove (invalid_vm); + hidden_vms.Add (invalid_vm); + } + invalids.Clear (); + + class_fields_valid = true; + foreach (ClassField field in class_fields) + if (!field.Validate ()) + class_fields_valid = false; + + foreach (InterfaceVM vm in interface_vms) + if (!vm.Validate ()) + invalids.Add (vm); + + foreach (InterfaceVM invalid_vm in invalids) { + interface_vms.Remove (invalid_vm); + hidden_vms.Add (invalid_vm); + } + invalids.Clear (); + + foreach (Signal sig in sigs.Values) { + if (!sig.Validate ()) { + Console.WriteLine ("in type " + QualifiedName); + invalids.Add (sig); + } + } + foreach (Signal sig in invalids) + sigs.Remove (sig.Name); + + return base.Validate (); + } + + public virtual bool ValidateForSubclass () + { + ArrayList invalids = new ArrayList (); + + foreach (Signal sig in sigs.Values) { + if (!sig.Validate ()) { + Console.WriteLine ("in type " + QualifiedName); + invalids.Add (sig); + } + } + foreach (Signal sig in invalids) + sigs.Remove (sig.Name); + invalids.Clear (); + + return true; + } + } +} diff --git a/generator/ObjectField.cs b/generator/ObjectField.cs new file mode 100644 index 0000000000..47e0156237 --- /dev/null +++ b/generator/ObjectField.cs @@ -0,0 +1,48 @@ +// GtkSharp.Generation.ObjectField.cs - autogenerated field glue +// +// 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.Collections; + using System.IO; + using System.Xml; + + public class ObjectField : FieldBase { + + public ObjectField (XmlElement elem, ClassBase container_type) : base (elem, container_type) + { + if (CType == "char*" || CType == "gchar*") + ctype = "const-" + CType; + } + + protected override bool Writable { + get { + return elem.GetAttribute ("writeable") == "true"; + } + } + + protected override string DefaultAccess { + get { + return "private"; + } + } + } +} + diff --git a/generator/ObjectGen.cs b/generator/ObjectGen.cs new file mode 100644 index 0000000000..7a7d561da0 --- /dev/null +++ b/generator/ObjectGen.cs @@ -0,0 +1,416 @@ +// GtkSharp.Generation.ObjectGen.cs - The Object Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// Copyright (c) 2003-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.Collections; + using System.IO; + using System.Text; + using System.Xml; + + public class ObjectGen : ObjectBase { + + private ArrayList custom_attrs = new ArrayList(); + private ArrayList strings = new ArrayList(); + private Hashtable childprops = new Hashtable(); + private static Hashtable dirs = new Hashtable (); + + public ObjectGen (XmlElement ns, XmlElement elem) : base (ns, elem, false) + { + foreach (XmlNode node in elem.ChildNodes) { + if (!(node is XmlElement)) continue; + XmlElement member = (XmlElement) node; + if (member.HasAttribute ("hidden") && member.GetAttribute ("hidden") == "1") continue; + + switch (node.Name) { + case "callback": + Statistics.IgnoreCount++; + break; + + case "custom-attribute": + custom_attrs.Add (member.InnerXml); + break; + + case "static-string": + strings.Add (node); + break; + + case "childprop": + string name = member.GetAttribute ("name"); + while (childprops.ContainsKey (name)) + name += "mangled"; + childprops.Add (name, new ChildProperty (member, this)); + break; + + default: + if (!IsNodeNameHandled (node.Name)) + Console.WriteLine ("Unexpected node " + node.Name + " in " + CName); + break; + } + } + } + + public override bool Validate () + { + ArrayList invalids = new ArrayList (); + + foreach (ChildProperty prop in childprops.Values) { + if (!prop.Validate ()) { + Console.WriteLine ("in Object " + QualifiedName); + invalids.Add (prop); + } + } + foreach (ChildProperty prop in invalids) + childprops.Remove (prop); + + return base.Validate (); + } + + private bool DisableVoidCtor { + get { + return Elem.HasAttribute ("disable_void_ctor"); + } + } + + private bool DisableGTypeCtor { + get { + return Elem.HasAttribute ("disable_gtype_ctor"); + } + } + + private class DirectoryInfo { + public string assembly_name; + public Hashtable objects; + + public DirectoryInfo (string assembly_name) { + this.assembly_name = assembly_name; + objects = new Hashtable (); + } + } + + private static DirectoryInfo GetDirectoryInfo (string dir, string assembly_name) + { + DirectoryInfo result; + + if (dirs.ContainsKey (dir)) { + result = dirs [dir] as DirectoryInfo; + if (result.assembly_name != assembly_name) { + Console.WriteLine ("Can't put multiple assemblies in one directory."); + return null; + } + + return result; + } + + result = new DirectoryInfo (assembly_name); + dirs.Add (dir, result); + + return result; + } + + public override void Generate (GenerationInfo gen_info) + { + gen_info.CurrentType = Name; + + string asm_name = gen_info.AssemblyName.Length == 0 ? NS.ToLower () + "-sharp" : gen_info.AssemblyName; + DirectoryInfo di = GetDirectoryInfo (gen_info.Dir, asm_name); + + StreamWriter sw = gen_info.Writer = gen_info.OpenStream (Name); + + sw.WriteLine ("namespace " + NS + " {"); + sw.WriteLine (); + sw.WriteLine ("\tusing System;"); + sw.WriteLine ("\tusing System.Collections;"); + sw.WriteLine ("\tusing System.Runtime.InteropServices;"); + sw.WriteLine (); + + SymbolTable table = SymbolTable.Table; + + sw.WriteLine ("#region Autogenerated code"); + if (IsDeprecated) + sw.WriteLine ("\t[Obsolete]"); + foreach (string attr in custom_attrs) + sw.WriteLine ("\t" + attr); + sw.Write ("\t{0} {1}class " + Name, IsInternal ? "internal" : "public", IsAbstract ? "abstract " : ""); + string cs_parent = table.GetCSType(Elem.GetAttribute("parent")); + if (cs_parent != "") { + di.objects.Add (CName, QualifiedName); + sw.Write (" : " + cs_parent); + } + foreach (string iface in interfaces) { + if (Parent != null && Parent.Implements (iface)) + continue; + sw.Write (", " + table.GetCSType (iface)); + } + foreach (string iface in managed_interfaces) { + if (Parent != null && Parent.Implements (iface)) + continue; + sw.Write (", " + iface); + } + sw.WriteLine (" {"); + sw.WriteLine (); + + GenCtors (gen_info); + GenProperties (gen_info, null); + GenFields (gen_info); + GenChildProperties (gen_info); + + bool has_sigs = (sigs != null && sigs.Count > 0); + if (!has_sigs) { + foreach (string iface in interfaces) { + InterfaceGen igen = table.GetClassGen (iface) as InterfaceGen; + if (igen != null && igen.Signals != null) { + has_sigs = true; + break; + } + } + } + + if (has_sigs && Elem.HasAttribute("parent")) { + GenSignals (gen_info, null); + } + + GenClassMembers (gen_info, cs_parent); + GenMethods (gen_info, null, null); + + if (interfaces.Count != 0) { + Hashtable all_methods = new Hashtable (); + foreach (Method m in Methods.Values) + all_methods[m.Name] = m; + Hashtable collisions = new Hashtable (); + foreach (string iface in interfaces) { + ClassBase igen = table.GetClassGen (iface); + foreach (Method m in igen.Methods.Values) { + Method collision = all_methods[m.Name] as Method; + if (collision != null && collision.Signature.Types == m.Signature.Types) + collisions[m.Name] = true; + else + all_methods[m.Name] = m; + } + } + + foreach (string iface in interfaces) { + if (Parent != null && Parent.Implements (iface)) + continue; + InterfaceGen igen = table.GetClassGen (iface) as InterfaceGen; + igen.GenMethods (gen_info, collisions, this); + igen.GenProperties (gen_info, this); + igen.GenSignals (gen_info, this); + igen.GenVirtualMethods (gen_info, this); + } + } + + foreach (XmlElement str in strings) { + sw.Write ("\t\tpublic static string " + str.GetAttribute ("name")); + sw.WriteLine (" {\n\t\t\t get { return \"" + str.GetAttribute ("value") + "\"; }\n\t\t}"); + } + + if (cs_parent != String.Empty && GetExpected (CName) != QualifiedName) { + sw.WriteLine (); + sw.WriteLine ("\t\tstatic " + Name + " ()"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tGtkSharp." + Studlify (asm_name) + ".ObjectManager.Initialize ();"); + sw.WriteLine ("\t\t}"); + } + + sw.WriteLine ("#endregion"); + AppendCustom (sw, gen_info.CustomDir); + + sw.WriteLine ("\t}"); + sw.WriteLine ("}"); + + sw.Close (); + gen_info.Writer = null; + Statistics.ObjectCount++; + } + + protected override void GenCtors (GenerationInfo gen_info) + { + if (!Elem.HasAttribute("parent")) + return; + + if (!DisableGTypeCtor) { + gen_info.Writer.WriteLine("\t\t[Obsolete]"); + gen_info.Writer.WriteLine("\t\tprotected " + Name + "(GLib.GType gtype) : base(gtype) {}"); + } + gen_info.Writer.WriteLine("\t\tpublic " + Name + "(IntPtr raw) : base(raw) {}"); + if (ctors.Count == 0 && !DisableVoidCtor) { + gen_info.Writer.WriteLine(); + gen_info.Writer.WriteLine("\t\tprotected " + Name + "() : base(IntPtr.Zero)"); + gen_info.Writer.WriteLine("\t\t{"); + gen_info.Writer.WriteLine("\t\t\tCreateNativeObject (new string [0], new GLib.Value [0]);"); + gen_info.Writer.WriteLine("\t\t}"); + } + gen_info.Writer.WriteLine(); + + base.GenCtors (gen_info); + } + + protected void GenChildProperties (GenerationInfo gen_info) + { + if (childprops.Count == 0) + return; + + StreamWriter sw = gen_info.Writer; + + ObjectGen child_ancestor = Parent as ObjectGen; + while (child_ancestor.CName != "GtkContainer" && + child_ancestor.childprops.Count == 0) + child_ancestor = child_ancestor.Parent as ObjectGen; + + sw.WriteLine ("\t\tpublic class " + Name + "Child : " + child_ancestor.NS + "." + child_ancestor.Name + "." + child_ancestor.Name + "Child {"); + sw.WriteLine ("\t\t\tprotected internal " + Name + "Child (Gtk.Container parent, Gtk.Widget child) : base (parent, child) {}"); + sw.WriteLine (""); + + foreach (ChildProperty prop in childprops.Values) + prop.Generate (gen_info, "\t\t\t", null); + + sw.WriteLine ("\t\t}"); + sw.WriteLine (""); + + sw.WriteLine ("\t\tpublic override Gtk.Container.ContainerChild this [Gtk.Widget child] {"); + sw.WriteLine ("\t\t\tget {"); + sw.WriteLine ("\t\t\t\treturn new " + Name + "Child (this, child);"); + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (""); + + } + + void GenClassMembers (GenerationInfo gen_info, string cs_parent) + { + GenVirtualMethods (gen_info, null); + + if (class_struct_name == null || !CanGenerateClassStruct) return; + StreamWriter sw = gen_info.Writer; + GenerateClassStruct (gen_info); + if (cs_parent == "") + sw.WriteLine ("\t\tstatic uint class_offset = 0;"); + else + sw.WriteLine ("\t\tstatic uint class_offset = ((GLib.GType) typeof ({0})).ClassSize;", cs_parent); + sw.WriteLine ("\t\tstatic Hashtable class_structs;"); + sw.WriteLine (); + sw.WriteLine ("\t\tstatic {0} GetClassStruct (GLib.GType gtype, bool use_cache)", class_struct_name); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tif (class_structs == null)"); + sw.WriteLine ("\t\t\t\tclass_structs = new Hashtable ();"); + sw.WriteLine (); + sw.WriteLine ("\t\t\tif (use_cache && class_structs.Contains (gtype))"); + sw.WriteLine ("\t\t\t\treturn ({0}) class_structs [gtype];", class_struct_name); + sw.WriteLine ("\t\t\telse {"); + sw.WriteLine ("\t\t\t\tIntPtr class_ptr = new IntPtr (gtype.ClassPtr.ToInt64 () + class_offset);"); + sw.WriteLine ("\t\t\t\t{0} class_struct = ({0}) Marshal.PtrToStructure (class_ptr, typeof ({0}));", class_struct_name); + sw.WriteLine ("\t\t\t\tif (use_cache)"); + sw.WriteLine ("\t\t\t\t\tclass_structs.Add (gtype, class_struct);"); + sw.WriteLine ("\t\t\t\treturn class_struct;"); + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + sw.WriteLine ("\t\tstatic void OverrideClassStruct (GLib.GType gtype, {0} class_struct)", class_struct_name); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tIntPtr class_ptr = new IntPtr (gtype.ClassPtr.ToInt64 () + class_offset);"); + sw.WriteLine ("\t\t\tMarshal.StructureToPtr (class_struct, class_ptr, false);"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + /* Keep this in sync with the one in glib/GType.cs */ + private static string GetExpected (string cname) + { + for (int i = 1; i < cname.Length; i++) { + if (Char.IsUpper (cname[i])) { + if (i == 1 && cname[0] == 'G') + return "GLib." + cname.Substring (1); + else + return cname.Substring (0, i) + "." + cname.Substring (i); + } + } + + throw new ArgumentException ("cname doesn't follow the NamespaceType capitalization style: " + cname); + } + + private static bool NeedsMap (Hashtable objs, string assembly_name) + { + foreach (string key in objs.Keys) + if (GetExpected (key) != ((string) objs[key])) + return true; + + return false; + } + + private static string Studlify (string name) + { + string result = ""; + + string[] subs = name.Split ('-'); + foreach (string sub in subs) + result += Char.ToUpper (sub[0]) + sub.Substring (1); + + return result; + } + + public static void GenerateMappers () + { + foreach (string dir in dirs.Keys) { + + DirectoryInfo di = dirs[dir] as DirectoryInfo; + + if (!NeedsMap (di.objects, di.assembly_name)) + continue; + + GenerationInfo gen_info = new GenerationInfo (dir, di.assembly_name); + + GenerateMapper (di, gen_info); + } + } + + private static void GenerateMapper (DirectoryInfo dir_info, GenerationInfo gen_info) + { + StreamWriter sw = gen_info.OpenStream ("ObjectManager"); + + sw.WriteLine ("namespace GtkSharp." + Studlify (dir_info.assembly_name) + " {"); + sw.WriteLine (); + sw.WriteLine ("\tpublic class ObjectManager {"); + sw.WriteLine (); + sw.WriteLine ("\t\tstatic bool initialized = false;"); + sw.WriteLine ("\t\t// Call this method from the appropriate module init function."); + sw.WriteLine ("\t\tpublic static void Initialize ()"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tif (initialized)"); + sw.WriteLine ("\t\t\t\treturn;"); + sw.WriteLine (""); + sw.WriteLine ("\t\t\tinitialized = true;"); + + foreach (string key in dir_info.objects.Keys) { + if (GetExpected(key) != ((string) dir_info.objects[key])) + sw.WriteLine ("\t\t\tGLib.GType.Register ({0}.GType, typeof ({0}));", dir_info.objects [key]); + } + + sw.WriteLine ("\t\t}"); + sw.WriteLine ("\t}"); + sw.WriteLine ("}"); + sw.Close (); + } + } +} + diff --git a/generator/OpaqueGen.cs b/generator/OpaqueGen.cs new file mode 100644 index 0000000000..55735415cf --- /dev/null +++ b/generator/OpaqueGen.cs @@ -0,0 +1,237 @@ +// GtkSharp.Generation.OpaqueGen.cs - The Opaque Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// +// 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.Collections; + using System.IO; + using System.Xml; + + public class OpaqueGen : HandleBase { + + public OpaqueGen (XmlElement ns, XmlElement elem) : base (ns, elem) {} + + public override string FromNative(string var, bool owned) + { + return var + " == IntPtr.Zero ? null : (" + QualifiedName + ") GLib.Opaque.GetOpaque (" + var + ", typeof (" + QualifiedName + "), " + (owned ? "true" : "false") + ")"; + } + + private bool DisableRawCtor { + get { + return Elem.HasAttribute ("disable_raw_ctor"); + } + } + + public override void Generate (GenerationInfo gen_info) + { + gen_info.CurrentType = Name; + + StreamWriter sw = gen_info.Writer = gen_info.OpenStream (Name); + + sw.WriteLine ("namespace " + NS + " {"); + sw.WriteLine (); + sw.WriteLine ("\tusing System;"); + sw.WriteLine ("\tusing System.Collections;"); + sw.WriteLine ("\tusing System.Runtime.InteropServices;"); + sw.WriteLine (); + + sw.WriteLine ("#region Autogenerated code"); + + SymbolTable table = SymbolTable.Table; + + Method ref_, unref, dispose; + GetSpecialMethods (out ref_, out unref, out dispose); + + if (IsDeprecated) + sw.WriteLine ("\t[Obsolete]"); + sw.Write ("\t{0}{1}class " + Name, IsInternal ? "internal " : "public ", IsAbstract ? "abstract " : String.Empty); + string cs_parent = table.GetCSType(Elem.GetAttribute("parent")); + if (cs_parent != "") + sw.Write (" : " + cs_parent); + else + sw.Write (" : GLib.Opaque"); + + foreach (string iface in managed_interfaces) { + if (Parent != null && Parent.Implements (iface)) + continue; + sw.Write (", " + iface); + } + + sw.WriteLine (" {"); + sw.WriteLine (); + + GenFields (gen_info); + GenMethods (gen_info, null, null); + GenCtors (gen_info); + + if (ref_ != null) { + ref_.GenerateImport (sw); + sw.WriteLine ("\t\tprotected override void Ref (IntPtr raw)"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tif (!Owned) {"); + sw.WriteLine ("\t\t\t\t" + ref_.CName + " (raw);"); + sw.WriteLine ("\t\t\t\tOwned = true;"); + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + + if (ref_.IsDeprecated) { + sw.WriteLine ("\t\t[Obsolete(\"" + QualifiedName + " is now refcounted automatically\")]"); + if (ref_.ReturnType == "void") + sw.WriteLine ("\t\tpublic void Ref () {}"); + else + sw.WriteLine ("\t\tpublic " + Name + " Ref () { return this; }"); + sw.WriteLine (); + } + } + + bool finalizer_needed = false; + + if (unref != null) { + unref.GenerateImport (sw); + sw.WriteLine ("\t\tprotected override void Unref (IntPtr raw)"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tif (Owned) {"); + sw.WriteLine ("\t\t\t\t" + unref.CName + " (raw);"); + sw.WriteLine ("\t\t\t\tOwned = false;"); + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + + if (unref.IsDeprecated) { + sw.WriteLine ("\t\t[Obsolete(\"" + QualifiedName + " is now refcounted automatically\")]"); + sw.WriteLine ("\t\tpublic void Unref () {}"); + sw.WriteLine (); + } + finalizer_needed = true; + } + + if (dispose != null) { + dispose.GenerateImport (sw); + sw.WriteLine ("\t\tprotected override void Free (IntPtr raw)"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\t" + dispose.CName + " (raw);"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + + if (dispose.IsDeprecated) { + sw.WriteLine ("\t\t[Obsolete(\"" + QualifiedName + " is now freed automatically\")]"); + sw.WriteLine ("\t\tpublic void " + dispose.Name + " () {}"); + sw.WriteLine (); + } + finalizer_needed = true; + } + + if (finalizer_needed) { + sw.WriteLine ("\t\tclass FinalizerInfo {"); + sw.WriteLine ("\t\t\tIntPtr handle;"); + sw.WriteLine (); + sw.WriteLine ("\t\t\tpublic FinalizerInfo (IntPtr handle)"); + sw.WriteLine ("\t\t\t{"); + sw.WriteLine ("\t\t\t\tthis.handle = handle;"); + sw.WriteLine ("\t\t\t}"); + sw.WriteLine (); + sw.WriteLine ("\t\t\tpublic bool Handler ()"); + sw.WriteLine ("\t\t\t{"); + if (dispose != null) + sw.WriteLine ("\t\t\t\t{0} (handle);", dispose.CName); + else if (unref != null) + sw.WriteLine ("\t\t\t\t{0} (handle);", unref.CName); + sw.WriteLine ("\t\t\t\treturn false;"); + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + sw.WriteLine ("\t\t~{0} ()", Name); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tif (!Owned)"); + sw.WriteLine ("\t\t\t\treturn;"); + sw.WriteLine ("\t\t\tFinalizerInfo info = new FinalizerInfo (Handle);"); + sw.WriteLine ("\t\t\tGLib.Timeout.Add (50, new GLib.TimeoutHandler (info.Handler));"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + +#if false + Method copy = Methods ["Copy"] as Method; + if (copy != null && copy.Parameters.Count == 0) { + sw.WriteLine ("\t\tprotected override GLib.Opaque Copy (IntPtr raw)"); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\tGLib.Opaque result = new " + QualifiedName + " (" + copy.CName + " (raw));"); + sw.WriteLine ("\t\t\tresult.Owned = true;"); + sw.WriteLine ("\t\t\treturn result;"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } +#endif + sw.WriteLine ("#endregion"); + + AppendCustom(sw, gen_info.CustomDir); + + sw.WriteLine ("\t}"); + sw.WriteLine ("}"); + + sw.Close (); + gen_info.Writer = null; + Statistics.OpaqueCount++; + } + + void GetSpecialMethods (out Method ref_, out Method unref, out Method dispose) + { + ref_ = CheckSpecialMethod (GetMethod ("Ref")); + unref = CheckSpecialMethod (GetMethod ("Unref")); + + dispose = GetMethod ("Free"); + if (dispose == null) { + dispose = GetMethod ("Destroy"); + if (dispose == null) + dispose = GetMethod ("Dispose"); + } + dispose = CheckSpecialMethod (dispose); + } + + Method CheckSpecialMethod (Method method) + { + if (method == null) + return null; + if (method.ReturnType != "void" && + method.ReturnType != QualifiedName) + return null; + if (method.Signature.ToString () != "") + return null; + + methods.Remove (method.Name); + return method; + } + + protected override void GenCtors (GenerationInfo gen_info) + { + if (!DisableRawCtor) { + gen_info.Writer.WriteLine("\t\tpublic " + Name + "(IntPtr raw) : base(raw) {}"); + gen_info.Writer.WriteLine(); + } + + base.GenCtors (gen_info); + } + + } +} + diff --git a/generator/Parameters.cs b/generator/Parameters.cs new file mode 100644 index 0000000000..3ebafbad77 --- /dev/null +++ b/generator/Parameters.cs @@ -0,0 +1,737 @@ +// GtkSharp.Generation.Parameters.cs - The Parameters Generation Class. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-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.Collections; + using System.IO; + using System.Xml; + + public class Parameter { + + private XmlElement elem; + + public Parameter (XmlElement e) + { + elem = e; + } + + string call_name; + public string CallName { + get { + if (call_name == null) + return Name; + else + return call_name; + } + set { + call_name = value; + } + } + + public string CType { + get { + string type = elem.GetAttribute("type"); + if (type == "void*") + type = "gpointer"; + return type; + } + } + + public string CSType { + get { + string cstype = SymbolTable.Table.GetCSType( elem.GetAttribute("type")); + if (cstype == "void") + cstype = "System.IntPtr"; + if (IsArray) { + if (IsParams) + cstype = "params " + cstype; + cstype += "[]"; + cstype = cstype.Replace ("ref ", ""); + } + return cstype; + } + } + + public IGeneratable Generatable { + get { + return SymbolTable.Table[CType]; + } + } + + public bool IsArray { + get { + return elem.HasAttribute("array") || elem.HasAttribute("null_term_array"); + } + } + + public bool IsEllipsis { + get { + return elem.HasAttribute("ellipsis"); + } + } + + public bool IsCount { + get { + + if (Name.StartsWith("n_")) + switch (CSType) { + case "int": + case "uint": + case "long": + case "ulong": + case "short": + case "ushort": + return true; + default: + return false; + } + else + return false; + } + } + + public bool IsDestroyNotify { + get { + return CType == "GDestroyNotify"; + } + } + + public bool IsLength { + get { + + if (Name.EndsWith("len") || Name.EndsWith("length")) + switch (CSType) { + case "int": + case "uint": + case "long": + case "ulong": + case "short": + case "ushort": + return true; + default: + return false; + } + else + return false; + } + } + + public bool IsParams { + get { + return elem.HasAttribute("params"); + } + } + + public bool IsString { + get { + return (CSType == "string"); + } + } + + public bool IsUserData { + get { + return CSType == "IntPtr" && (Name.EndsWith ("data") || Name.EndsWith ("data_or_owner")); + } + } + + public virtual string MarshalType { + get { + string type = SymbolTable.Table.GetMarshalType( elem.GetAttribute("type")); + if (type == "void" || Generatable is IManualMarshaler) + type = "IntPtr"; + if (IsArray) { + type += "[]"; + type = type.Replace ("ref ", ""); + } + return type; + } + } + + public string Name { + get { + return SymbolTable.Table.MangleName (elem.GetAttribute("name")); + } + } + + public bool Owned { + get { + return elem.GetAttribute ("owned") == "true"; + } + } + + public virtual string NativeSignature { + get { + string sig = MarshalType + " " + Name; + if (PassAs != String.Empty) + sig = PassAs + " " + sig; + return sig; + } + } + + public string PropertyName { + get { + return elem.GetAttribute("property_name"); + } + } + + string pass_as; + + public string PassAs { + get { + if (pass_as != null) + return pass_as; + + if (elem.HasAttribute ("pass_as")) + return elem.GetAttribute ("pass_as"); + + if (IsArray || CSType.EndsWith ("IntPtr")) + return ""; + + if (CType.EndsWith ("*") && (Generatable is SimpleGen || Generatable is EnumGen)) + return "out"; + + return ""; + } + set { + pass_as = value; + } + } + + string scope; + public string Scope { + get { + if (scope == null) + scope = elem.GetAttribute ("scope"); + return scope; + } + set { + scope = value; + } + } + + public virtual string[] Prepare { + get { + IGeneratable gen = Generatable; + if (gen is IManualMarshaler) { + string result = "IntPtr native_" + CallName; + if (PassAs != "out") + result += " = " + (gen as IManualMarshaler).AllocNative (CallName); + return new string [] { result + ";" }; + } else if (PassAs == "out" && CSType != MarshalType) { + return new string [] { gen.MarshalType + " native_" + CallName + ";" }; + } else if (PassAs == "ref" && CSType != MarshalType) { + return new string [] { gen.MarshalType + " native_" + CallName + " = (" + gen.MarshalType + ") " + CallName + ";" }; + } + + return new string [0]; + } + } + + public virtual string CallString { + get { + string call_parm; + + IGeneratable gen = Generatable; + if (gen is CallbackGen) + return SymbolTable.Table.CallByName (CType, CallName + "_wrapper"); + else if (PassAs != String.Empty) { + call_parm = PassAs + " "; + if (CSType != MarshalType) + call_parm += "native_"; + call_parm += CallName; + } else if (gen is IManualMarshaler) + call_parm = "native_" + CallName; + else + call_parm = SymbolTable.Table.CallByName(CType, CallName); + + return call_parm; + } + } + + public virtual string[] Finish { + get { + IGeneratable gen = Generatable; + if (gen is IManualMarshaler) { + string[] result = new string [PassAs == "ref" ? 2 : 1]; + int i = 0; + if (PassAs != String.Empty) + result [i++] = CallName + " = " + Generatable.FromNative ("native_" + CallName) + ";"; + if (PassAs != "out") + result [i] = (gen as IManualMarshaler).ReleaseNative ("native_" + CallName) + ";"; + return result; + } else if (PassAs != String.Empty && MarshalType != CSType) + return new string [] { CallName + " = " + gen.FromNative ("native_" + CallName) + ";" }; + return new string [0]; + } + } + + public string FromNative (string var) + { + if (Generatable == null) + return String.Empty; + else if (Generatable is HandleBase) + return ((HandleBase)Generatable).FromNative (var, Owned); + else + return Generatable.FromNative (var); + } + + public string StudlyName { + get { + string name = elem.GetAttribute("name"); + string[] segs = name.Split('_'); + string studly = ""; + foreach (string s in segs) { + if (s.Trim () == "") + continue; + studly += (s.Substring(0,1).ToUpper() + s.Substring(1)); + } + return studly; + + } + } + } + + public class ArrayParameter : Parameter { + + bool null_terminated; + + public ArrayParameter (XmlElement elem) : base (elem) + { + null_terminated = elem.HasAttribute ("null_term_array"); + } + + public override string MarshalType { + get { + if (Generatable is StructBase) + return CSType; + else + return base.MarshalType; + } + } + + bool NullTerminated { + get { + return null_terminated; + } + } + + public override string[] Prepare { + get { + if (CSType == MarshalType) + return new string [0]; + + ArrayList result = new ArrayList (); + result.Add (String.Format ("int cnt_{0} = {0} == null ? 0 : {0}.Length;", CallName)); + result.Add (String.Format ("{0}[] native_{1} = new {0} [cnt_{1}" + (NullTerminated ? " + 1" : "") + "];", MarshalType.TrimEnd('[', ']'), CallName)); + result.Add (String.Format ("for (int i = 0; i < cnt_{0}; i++)", CallName)); + IGeneratable gen = Generatable; + if (gen is IManualMarshaler) + result.Add (String.Format ("\tnative_{0} [i] = {1};", CallName, (gen as IManualMarshaler).AllocNative (CallName + "[i]"))); + else + result.Add (String.Format ("\tnative_{0} [i] = {1};", CallName, gen.CallByName (CallName + "[i]"))); + + if (NullTerminated) + result.Add (String.Format ("native_{0} [cnt_{0}] = IntPtr.Zero;", CallName)); + return (string[]) result.ToArray (typeof (string)); + } + } + + public override string CallString { + get { + if (CSType != MarshalType) + return "native_" + CallName; + else + return CallName; + } + } + + public override string[] Finish { + get { + if (CSType == MarshalType) + return new string [0]; + + IGeneratable gen = Generatable; + if (gen is IManualMarshaler) { + string [] result = new string [4]; + result [0] = "for (int i = 0; i < native_" + CallName + ".Length" + (NullTerminated ? " - 1" : "") + "; i++) {"; + result [1] = "\t" + CallName + " [i] = " + Generatable.FromNative ("native_" + CallName + "[i]") + ";"; + result [2] = "\t" + (gen as IManualMarshaler).ReleaseNative ("native_" + CallName + "[i]") + ";"; + result [3] = "}"; + return result; + } + + return new string [0]; + } + } + } + + public class ArrayCountPair : ArrayParameter { + + XmlElement count_elem; + bool invert; + + public ArrayCountPair (XmlElement array_elem, XmlElement count_elem, bool invert) : base (array_elem) + { + this.count_elem = count_elem; + this.invert = invert; + } + + string CountNativeType { + get { + return SymbolTable.Table.GetMarshalType(count_elem.GetAttribute("type")); + } + } + + string CountType { + get { + return SymbolTable.Table.GetCSType(count_elem.GetAttribute("type")); + } + } + + string CountCast { + get { + if (CountType == "int") + return String.Empty; + else + return "(" + CountType + ") "; + } + } + + string CountName { + get { + return SymbolTable.Table.MangleName (count_elem.GetAttribute("name")); + } + } + + string CallCount (string name) + { + string result = CountCast + "(" + name + " == null ? 0 : " + name + ".Length)"; + IGeneratable gen = SymbolTable.Table[count_elem.GetAttribute("type")]; + return gen.CallByName (result); + } + + public override string CallString { + get { + if (invert) + return CallCount (CallName) + ", " + base.CallString; + else + return base.CallString + ", " + CallCount (CallName); + } + } + + public override string NativeSignature { + get { + if (invert) + return CountNativeType + " " + CountName + ", " + MarshalType + " " + Name; + else + return MarshalType + " " + Name + ", " + CountNativeType + " " + CountName; + } + } + } + + public class ErrorParameter : Parameter { + + public ErrorParameter (XmlElement elem) : base (elem) + { + PassAs = "out"; + } + + public override string CallString { + get { + return "out error"; + } + } + } + + public class StructParameter : Parameter { + + public StructParameter (XmlElement elem) : base (elem) {} + + public override string MarshalType { + get { + return "IntPtr"; + } + } + + public override string[] Prepare { + get { + if (PassAs == "out") + return new string [] { "IntPtr native_" + CallName + " = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (" + Generatable.QualifiedName + ")));"}; + else + return new string [] { "IntPtr native_" + CallName + " = " + (Generatable as IManualMarshaler).AllocNative (CallName) + ";"}; + } + } + + public override string CallString { + get { + return "native_" + CallName; + } + } + + public override string[] Finish { + get { + string[] result = new string [2]; + result [0] = CallName + " = " + FromNative ("native_" + CallName) + ";"; + result [1] = (Generatable as IManualMarshaler).ReleaseNative ("native_" + CallName) + ";"; + return result; + } + } + + public override string NativeSignature { + get { + return "IntPtr " + CallName; + } + } + } + + public class Parameters : IEnumerable { + + ArrayList param_list = new ArrayList (); + XmlElement elem; + bool first_is_instance; + + public Parameters (XmlElement elem) : this (elem, false) { } + + public Parameters (XmlElement elem, bool first_is_instance) + { + if (elem == null) + valid = true; + this.elem = elem; + this.first_is_instance = first_is_instance; + if (first_is_instance) + is_static = false; + } + + public int Count { + get { + return param_list.Count; + } + } + + public int VisibleCount { + get { + int visible = 0; + foreach (Parameter p in this) { + if (!IsHidden (p)) + visible++; + } + return visible; + } + } + + public Parameter this [int idx] { + get { + return param_list [idx] as Parameter; + } + } + + public bool IsHidden (Parameter p) + { + int idx = param_list.IndexOf (p); + + if (idx > 0 && p.IsLength && p.PassAs == String.Empty && this [idx - 1].IsString) + return true; + + if (p.IsCount && ((idx > 0 && this [idx - 1].IsArray) || + (idx < Count - 1 && this [idx + 1].IsArray))) + return true; + + if (p.CType == "GError**") + return true; + + if (HasCB || HideData) { + if (p.IsUserData && (idx == Count - 1)) + return true; + if (p.IsUserData && (idx == Count - 2) && this [Count - 1] is ErrorParameter) + return true; + if (p.IsUserData && idx > 0 && + this [idx - 1].Generatable is CallbackGen) + return true; + if (p.IsDestroyNotify && (idx == Count - 1) && + this [idx - 1].IsUserData) + return true; + } + + return false; + } + + bool has_cb; + public bool HasCB { + get { return has_cb; } + set { has_cb = value; } + } + + public bool HasOutParam { + get { + foreach (Parameter p in this) + if (p.PassAs == "out") + return true; + return false; + } + } + + bool hide_data; + public bool HideData { + get { return hide_data; } + set { hide_data = value; } + } + + bool is_static; + public bool Static { + get { return is_static; } + set { is_static = value; } + } + + void Clear () + { + elem = null; + param_list.Clear (); + param_list = null; + } + + public IEnumerator GetEnumerator () + { + return param_list.GetEnumerator (); + } + + bool valid = false; + + public bool Validate () + { + if (valid) + return true; + + if (elem == null) + return false; + + for (int i = first_is_instance ? 1 : 0; i < elem.ChildNodes.Count; i++) { + XmlElement parm = elem.ChildNodes [i] as XmlElement; + if (parm == null || parm.Name != "parameter") + continue; + Parameter p = new Parameter (parm); + + if (p.IsEllipsis) { + Console.Write("Ellipsis parameter "); + Clear (); + return false; + } + + if ((p.CSType == "") || (p.Name == "") || + (p.MarshalType == "") || (SymbolTable.Table.CallByName(p.CType, p.Name) == "")) { + Console.Write ("Invalid parameter {0} of type {1}", p.Name, p.CType); + Clear (); + return false; + } + + IGeneratable gen = p.Generatable; + + if (p.IsArray) { + p = new ArrayParameter (parm); + if (i < elem.ChildNodes.Count - 1) { + XmlElement next = elem.ChildNodes [i + 1] as XmlElement; + if (next != null || next.Name == "parameter") { + Parameter c = new Parameter (next); + if (c.IsCount) { + p = new ArrayCountPair (parm, next, false); + i++; + } + } + } + } else if (p.IsCount && i < elem.ChildNodes.Count - 1) { + XmlElement next = elem.ChildNodes [i + 1] as XmlElement; + if (next != null || next.Name == "parameter") { + Parameter a = new Parameter (next); + if (a.IsArray) { + p = new ArrayCountPair (next, parm, true); + i++; + } + } + } else if (p.CType == "GError**") + p = new ErrorParameter (parm); + else if (gen is StructBase || gen is ByRefGen) { + p = new StructParameter (parm); + } else if (gen is CallbackGen) { + has_cb = true; + } + param_list.Add (p); + } + + if (has_cb && Count > 2 && this [Count - 3].Generatable is CallbackGen && this [Count - 2].IsUserData && this [Count - 1].IsDestroyNotify) + this [Count - 3].Scope = "notified"; + + valid = true; + return true; + } + + public bool IsAccessor { + get { + return VisibleCount == 1 && AccessorParam.PassAs == "out"; + } + } + + public Parameter AccessorParam { + get { + foreach (Parameter p in this) { + if (!IsHidden (p)) + return p; + } + return null; + } + } + + public string AccessorReturnType { + get { + Parameter p = AccessorParam; + if (p != null) + return p.CSType; + else + return null; + } + } + + public string AccessorName { + get { + Parameter p = AccessorParam; + if (p != null) + return p.Name; + else + return null; + } + } + + public string ImportSignature { + get { + if (Count == 0) + return String.Empty; + + string[] result = new string [Count]; + for (int i = 0; i < Count; i++) + result [i] = this [i].NativeSignature; + + return String.Join (", ", result); + } + } + } +} + diff --git a/generator/Parser.cs b/generator/Parser.cs new file mode 100644 index 0000000000..85c13cb25f --- /dev/null +++ b/generator/Parser.cs @@ -0,0 +1,185 @@ +// GtkSharp.Generation.Parser.cs - The XML Parsing engine. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// Copyright (c) 2003 Ximian 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.Collections; + using System.IO; + using System.Xml; + + public class Parser { + const int curr_parser_version = 2; + + private XmlDocument Load (string filename) + { + XmlDocument doc = new XmlDocument (); + + try { + Stream stream = File.OpenRead (filename); + doc.Load (stream); + stream.Close (); + } catch (XmlException e) { + Console.WriteLine ("Invalid XML file."); + Console.WriteLine (e); + doc = null; + } + + return doc; + } + + public IGeneratable[] Parse (string filename) + { + XmlDocument doc = Load (filename); + if (doc == null) + return null; + + XmlElement root = doc.DocumentElement; + + if ((root == null) || !root.HasChildNodes) { + Console.WriteLine ("No Namespaces found."); + return null; + } + + int parser_version; + if (root.HasAttribute ("parser_version")) { + try { + parser_version = int.Parse (root.GetAttribute ("parser_version")); + } catch { + Console.WriteLine ("ERROR: Unable to parse parser_version attribute value \"{0}\" to a number. Input file {1} will be ignored", root.GetAttribute ("parser_version"), filename); + return null; + } + } else + parser_version = 1; + + if (parser_version > curr_parser_version) + Console.WriteLine ("WARNING: The input file {0} was created by a parser that was released after this version of the generator. Consider updating the code generator if you experience problems.", filename); + + ArrayList gens = new ArrayList (); + + foreach (XmlNode child in root.ChildNodes) { + XmlElement elem = child as XmlElement; + if (elem == null) + continue; + + switch (child.Name) { + case "namespace": + gens.AddRange (ParseNamespace (elem)); + break; + case "symbol": + gens.Add (ParseSymbol (elem)); + break; + default: + Console.WriteLine ("Parser::Parse - Unexpected child node: " + child.Name); + break; + } + } + + return (IGeneratable[]) gens.ToArray (typeof (IGeneratable)); + } + + private ArrayList ParseNamespace (XmlElement ns) + { + ArrayList result = new ArrayList (); + + foreach (XmlNode def in ns.ChildNodes) { + + XmlElement elem = def as XmlElement; + if (elem == null) + continue; + + if (elem.HasAttribute("hidden")) + continue; + + bool is_opaque = false; + if (elem.GetAttribute ("opaque") == "true" || + elem.GetAttribute ("opaque") == "1") + is_opaque = true; + + switch (def.Name) { + case "alias": + string aname = elem.GetAttribute("cname"); + string atype = elem.GetAttribute("type"); + if ((aname == "") || (atype == "")) + continue; + result.Add (new AliasGen (aname, atype)); + break; + case "boxed": + result.Add (is_opaque ? new OpaqueGen (ns, elem) as object : new BoxedGen (ns, elem) as object); + break; + case "callback": + result.Add (new CallbackGen (ns, elem)); + break; + case "enum": + result.Add (new EnumGen (ns, elem)); + break; + case "interface": + result.Add (new InterfaceGen (ns, elem)); + break; + case "object": + result.Add (new ObjectGen (ns, elem)); + break; + case "class": + result.Add (new ClassGen (ns, elem)); + break; + case "struct": + result.Add (is_opaque ? new OpaqueGen (ns, elem) as object : new StructGen (ns, elem) as object); + break; + default: + Console.WriteLine ("Parser::ParseNamespace - Unexpected node: " + def.Name); + break; + } + } + + return result; + } + + private IGeneratable ParseSymbol (XmlElement symbol) + { + string type = symbol.GetAttribute ("type"); + string cname = symbol.GetAttribute ("cname"); + string name = symbol.GetAttribute ("name"); + IGeneratable result = null; + + if (type == "simple") { + if (symbol.HasAttribute ("default_value")) + result = new SimpleGen (cname, name, symbol.GetAttribute ("default_value")); + else { + Console.WriteLine ("Simple type element " + cname + " has no specified default value"); + result = new SimpleGen (cname, name, String.Empty); + } + } else if (type == "manual") + result = new ManualGen (cname, name); + else if (type == "alias") + result = new AliasGen (cname, name); + else if (type == "marshal") { + string mtype = symbol.GetAttribute ("marshal_type"); + string call = symbol.GetAttribute ("call_fmt"); + string from = symbol.GetAttribute ("from_fmt"); + result = new MarshalGen (cname, name, mtype, call, from); + } else + Console.WriteLine ("Parser::ParseSymbol - Unexpected symbol type " + type); + + return result; + } + } +} diff --git a/generator/Property.cs b/generator/Property.cs new file mode 100644 index 0000000000..fbf940b817 --- /dev/null +++ b/generator/Property.cs @@ -0,0 +1,193 @@ +// GtkSharp.Generation.Property.cs - The Property Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-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.Collections; + using System.IO; + using System.Xml; + + public class Property : PropertyBase { + + public Property (XmlElement elem, ClassBase container_type) : base (elem, container_type) {} + + public bool Validate () + { + if (CSType == "" && !Hidden) { + Console.Write("Property has unknown Type {0} ", CType); + Statistics.ThrottledCount++; + return false; + } + + return true; + } + + bool Readable { + get { + return elem.GetAttribute ("readable") == "true"; + } + } + + bool Writable { + get { + return elem.GetAttribute ("writeable") == "true" && + !elem.HasAttribute ("construct-only"); + } + } + + bool IsDeprecated { + get { + return !container_type.IsDeprecated && + (elem.GetAttribute ("deprecated") == "1" || + elem.GetAttribute ("deprecated") == "true"); + } + } + + protected virtual string PropertyAttribute (string qpname) { + return "[GLib.Property (" + qpname + ")]"; + } + + protected virtual string RawGetter (string qpname) { + return "GetProperty (" + qpname + ")"; + } + + protected virtual string RawSetter (string qpname) { + return "SetProperty(" + qpname + ", val)"; + } + + public void GenerateDecl (StreamWriter sw, string indent) + { + if (Hidden || (!Readable && !Writable)) + return; + + string name = Name; + if (name == container_type.Name) + name += "Prop"; + + sw.WriteLine (indent + CSType + " " + name + " {"); + sw.Write (indent + "\t"); + if (Readable || Getter != null) + sw.Write ("get; "); + if (Writable || Setter != null) + sw.Write ("set;"); + sw.WriteLine (); + sw.WriteLine (indent + "}"); + } + + public void Generate (GenerationInfo gen_info, string indent, ClassBase implementor) + { + SymbolTable table = SymbolTable.Table; + StreamWriter sw = gen_info.Writer; + + if (Hidden || (!Readable && !Writable)) + return; + + string modifiers = ""; + + if (IsNew || (container_type.Parent != null && container_type.Parent.GetPropertyRecursively (Name) != null)) + modifiers = "new "; + else if (implementor != null && implementor.Parent != null && implementor.Parent.GetPropertyRecursively (Name) != null) + modifiers = "new "; + + string name = Name; + if (name == container_type.Name) { + name += "Prop"; + } + string qpname = "\"" + CName + "\""; + + string v_type = ""; + if (table.IsInterface (CType)) { + v_type = "(GLib.Object)"; + } else if (table.IsOpaque (CType)) { + v_type = "(GLib.Opaque)"; + } else if (table.IsEnum (CType)) { + v_type = "(Enum)"; + } + + GenerateImports (gen_info, indent); + + if (IsDeprecated || + (Getter != null && Getter.IsDeprecated) || + (Setter != null && Setter.IsDeprecated)) + sw.WriteLine (indent + "[Obsolete]"); + sw.WriteLine (indent + PropertyAttribute (qpname)); + sw.WriteLine (indent + "public " + modifiers + CSType + " " + name + " {"); + indent += "\t"; + + if (Getter != null) { + sw.Write(indent + "get "); + Getter.GenerateBody(gen_info, implementor, "\t"); + sw.WriteLine(); + } else if (Readable) { + sw.WriteLine(indent + "get {"); + sw.WriteLine(indent + "\tGLib.Value val = " + RawGetter (qpname) + ";"); + if (table.IsOpaque (CType) || table.IsBoxed (CType)) { + sw.WriteLine(indent + "\t" + CSType + " ret = (" + CSType + ") val;"); + } else if (table.IsInterface (CType)) { + // Do we have to dispose the GLib.Object from the GLib.Value? + sw.WriteLine (indent + "\t{0} ret = {0}Adapter.GetObject ((GLib.Object) val);", CSType); + } else { + sw.Write(indent + "\t" + CSType + " ret = "); + sw.Write ("(" + CSType + ") "); + if (v_type != "") { + sw.Write(v_type + " "); + } + sw.WriteLine("val;"); + } + + sw.WriteLine(indent + "\tval.Dispose ();"); + sw.WriteLine(indent + "\treturn ret;"); + sw.WriteLine(indent + "}"); + } + + if (Setter != null) { + sw.Write(indent + "set "); + Setter.GenerateBody(gen_info, implementor, "\t"); + sw.WriteLine(); + } else if (Writable) { + sw.WriteLine(indent + "set {"); + sw.Write(indent + "\tGLib.Value val = "); + if (table.IsBoxed (CType)) { + sw.WriteLine("(GLib.Value) value;"); + } else if (table.IsOpaque (CType)) { + sw.WriteLine("new GLib.Value(value, \"{0}\");", CType); + } else { + sw.Write("new GLib.Value("); + if (v_type != "" && !(table.IsObject (CType) || table.IsInterface (CType) || table.IsOpaque (CType))) { + sw.Write(v_type + " "); + } + sw.WriteLine("value);"); + } + sw.WriteLine(indent + "\t" + RawSetter (qpname) + ";"); + sw.WriteLine(indent + "\tval.Dispose ();"); + sw.WriteLine(indent + "}"); + } + + sw.WriteLine(indent.Substring (1) + "}"); + sw.WriteLine(); + + Statistics.PropCount++; + } + } +} + diff --git a/generator/PropertyBase.cs b/generator/PropertyBase.cs new file mode 100644 index 0000000000..ef106f6bca --- /dev/null +++ b/generator/PropertyBase.cs @@ -0,0 +1,116 @@ +// GtkSharp.Generation.PropertyBase.cs - base class for properties and +// fields +// +// 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 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.Xml; + + public abstract class PropertyBase { + + protected XmlElement elem; + protected ClassBase container_type; + + public PropertyBase (XmlElement elem, ClassBase container_type) + { + this.elem = elem; + this.container_type = container_type; + } + + public string Name { + get { + return elem.GetAttribute ("name"); + } + } + + public string CName { + get { + return elem.GetAttribute ("cname"); + } + } + + protected string ctype; + public string CType { + get { + if (ctype == null) { + if (elem.GetAttribute("bits") == "1") + ctype = "gboolean"; + else + ctype = elem.GetAttribute("type"); + } + return ctype; + } + } + + protected string cstype; + public string CSType { + get { + if (Getter != null) + return Getter.Signature.IsAccessor ? Getter.Signature.AccessorType : Getter.ReturnType; + else if (Setter != null) + return Setter.Signature.Types; + else if (cstype == null) + cstype = SymbolTable.Table.GetCSType (CType); + return cstype; + } + } + + public bool Hidden { + get { + return elem.HasAttribute("hidden"); + } + } + + protected bool IsNew { + get { + return elem.HasAttribute("new_flag"); + } + } + + protected Method Getter { + get { + Method getter = container_type.GetMethod ("Get" + Name); + if (getter != null && getter.Name == "Get" + Name && getter.IsGetter) + return getter; + else + return null; + } + } + + protected Method Setter { + get { + Method setter = container_type.GetMethod ("Set" + Name); + if (setter != null && setter.Name == "Set" + Name && setter.IsSetter && (Getter == null || setter.Signature.Types == CSType)) + return setter; + else + return null; + } + } + + protected virtual void GenerateImports (GenerationInfo gen_info, string indent) + { + if (Getter != null) + Getter.GenerateImport (gen_info.Writer); + if (Setter != null) + Setter.GenerateImport (gen_info.Writer); + } + } +} + diff --git a/generator/ReturnValue.cs b/generator/ReturnValue.cs new file mode 100644 index 0000000000..bbf0c29050 --- /dev/null +++ b/generator/ReturnValue.cs @@ -0,0 +1,168 @@ +// GtkSharp.Generation.ReturnValue.cs - The ReturnValue Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2004-2005 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.Xml; + + public class ReturnValue { + + + bool is_null_term; + bool is_array; + bool elements_owned; + bool owned; + string ctype = String.Empty; + string element_ctype = String.Empty; + + public ReturnValue (XmlElement elem) + { + if (elem != null) { + is_null_term = elem.HasAttribute ("null_term_array"); + is_array = elem.HasAttribute ("array"); + elements_owned = elem.GetAttribute ("elements_owned") == "true"; + owned = elem.GetAttribute ("owned") == "true"; + ctype = elem.GetAttribute("type"); + element_ctype = elem.GetAttribute ("element_type"); + } + } + + public string CType { + get { + return ctype; + } + } + + public string CSType { + get { + if (IGen == null) + return String.Empty; + + if (ElementType != String.Empty) + return ElementType + "[]"; + + return IGen.QualifiedName + (is_array || is_null_term ? "[]" : String.Empty); + } + } + + public string DefaultValue { + get { + if (IGen == null) + return String.Empty; + return IGen.DefaultValue; + } + } + + string ElementType { + get { + if (element_ctype.Length > 0) + return SymbolTable.Table.GetCSType (element_ctype); + + return String.Empty; + } + } + + IGeneratable igen; + public IGeneratable IGen { + get { + if (igen == null) + igen = SymbolTable.Table [CType]; + return igen; + } + } + + public bool IsVoid { + get { + return CSType == "void"; + } + } + + public string MarshalType { + get { + if (IGen == null) + return String.Empty; + else if (is_null_term) + return "IntPtr"; + return IGen.MarshalReturnType + (is_array ? "[]" : String.Empty); + } + } + + public string ToNativeType { + get { + if (IGen == null) + return String.Empty; + return IGen.ToNativeReturnType + (is_array || is_null_term ? "[]" : String.Empty); + } + } + + public string FromNative (string var) + { + if (IGen == null) + return String.Empty; + + if (ElementType != String.Empty) { + string args = (owned ? "true" : "false") + ", " + (elements_owned ? "true" : "false"); + if (IGen.QualifiedName == "GLib.PtrArray") + return String.Format ("({0}[]) GLib.Marshaller.PtrArrayToArray ({1}, {2}, typeof({0}))", ElementType, var, args); + else + return String.Format ("({0}[]) GLib.Marshaller.ListPtrToArray ({1}, typeof({2}), {3}, typeof({4}))", ElementType, var, IGen.QualifiedName, args, element_ctype == "gfilename*" ? "GLib.ListBase.FilenameString" : ElementType); + } else if (IGen is HandleBase) + return ((HandleBase)IGen).FromNative (var, owned); + else if (is_null_term) + return String.Format ("GLib.Marshaller.NullTermPtrToStringArray ({0}, {1})", var, owned ? "true" : "false"); + else + 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") + ", " + (elements_owned ? "true" : "false"); + var = "new " + IGen.QualifiedName + "(" + var + args + ")"; + } else if (is_null_term) + return String.Format ("GLib.Marshaller.StringArrayToNullTermPointer ({0})", var); + + if (IGen is IManualMarshaler) + return (IGen as IManualMarshaler).AllocNative (var); + else if (IGen is ObjectGen && owned) + return var + " == null ? IntPtr.Zero : " + var + ".OwnedHandle"; + else if (IGen is OpaqueGen && owned) + return var + " == null ? IntPtr.Zero : " + var + ".OwnedCopy"; + else + return IGen.ToNativeReturn (var); + } + + public bool Validate () + { + if (MarshalType == "" || CSType == "") { + Console.Write("rettype: " + CType); + return false; + } + + return true; + } + } +} + diff --git a/generator/Signal.cs b/generator/Signal.cs new file mode 100644 index 0000000000..b2ee0aadf8 --- /dev/null +++ b/generator/Signal.cs @@ -0,0 +1,327 @@ +// GtkSharp.Generation.Signal.cs - The Signal Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// Copyright (c) 2003-2005 Novell, Inc. +// 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 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.Collections; + using System.IO; + using System.Xml; + + public class Signal { + + bool marshaled; + string name; + XmlElement elem; + ReturnValue retval; + Parameters parms; + ObjectBase container_type; + + public Signal (XmlElement elem, ObjectBase container_type) + { + this.elem = elem; + name = elem.GetAttribute ("name"); + marshaled = elem.GetAttribute ("manual") == "true"; + retval = new ReturnValue (elem ["return-type"]); + parms = new Parameters (elem["parameters"], container_type.ParserVersion == 1 ? true : false); + this.container_type = container_type; + } + + bool Marshaled { + get { return marshaled; } + } + + public string Name { + get { + return name; + } + set { + name = value; + } + } + + public bool Validate () + { + if (Name == "") { + Console.Write ("Nameless signal "); + Statistics.ThrottledCount++; + return false; + } + + if (!parms.Validate () || !retval.Validate ()) { + Console.Write (" in signal " + Name + " "); + Statistics.ThrottledCount++; + return false; + } + + return true; + } + + public void GenerateDecl (StreamWriter sw) + { + if (elem.HasAttribute("new_flag") || (container_type != null && container_type.GetSignalRecursively (Name) != null)) + sw.Write("new "); + + sw.WriteLine ("\t\tevent " + EventHandlerQualifiedName + " " + Name + ";"); + } + + public string CName { + get { + return "\"" + elem.GetAttribute("cname") + "\""; + } + } + + string CallbackSig { + get { + string result = ""; + for (int i = 0; i < parms.Count; i++) { + if (i > 0) + result += ", "; + + Parameter p = parms [i]; + if (p.PassAs != "" && !(p.Generatable is StructBase)) + result += p.PassAs + " "; + result += (p.MarshalType + " arg" + i); + } + + return result; + } + } + + string CallbackName { + get { return Name + "SignalCallback"; } + } + + string DelegateName { + get { return Name + "SignalDelegate"; } + } + + private string EventArgsName { + get { + if (IsEventHandler) + return "EventArgs"; + else + return Name + "Args"; + } + } + + private string EventArgsQualifiedName { + get { + if (IsEventHandler) + return "System.EventArgs"; + else + return container_type.NS + "." + Name + "Args"; + } + } + + private string EventHandlerName { + get { + if (IsEventHandler) + return "EventHandler"; + else if (SymbolTable.Table [container_type.NS + Name + "Handler"] != null) + return Name + "EventHandler"; + else + return Name + "Handler"; + } + } + + private string EventHandlerQualifiedName { + get { + if (IsEventHandler) + return "System.EventHandler"; + else + return container_type.NS + "." + EventHandlerName; + } + } + + private bool IsEventHandler { + get { + return retval.CSType == "void" && parms.Count == 0; + } + } + + public string GenArgsInitialization (StreamWriter sw) + { + if (parms.Count > 0) + sw.WriteLine("\t\t\t\targs.Args = new object[" + parms.Count + "];"); + string finish = ""; + for (int idx = 0; idx < parms.Count; idx++) { + Parameter p = parms [idx]; + IGeneratable igen = p.Generatable; + if (p.PassAs != "out") { + if (igen is ManualGen) { + sw.WriteLine("\t\t\t\tif (arg{0} == IntPtr.Zero)", idx); + sw.WriteLine("\t\t\t\t\targs.Args[{0}] = null;", idx); + sw.WriteLine("\t\t\t\telse {"); + sw.WriteLine("\t\t\t\t\targs.Args[" + idx + "] = " + p.FromNative ("arg" + idx) + ";"); + sw.WriteLine("\t\t\t\t}"); + } else + sw.WriteLine("\t\t\t\targs.Args[" + idx + "] = " + p.FromNative ("arg" + idx) + ";"); + } + if (igen is StructBase && p.PassAs == "ref") + finish += "\t\t\t\tif (arg" + idx + " != IntPtr.Zero) System.Runtime.InteropServices.Marshal.StructureToPtr (args.Args[" + (idx-1) + "], arg" + idx + ", false);\n"; + else if (p.PassAs != "") + finish += "\t\t\t\targ" + idx + " = " + igen.ToNativeReturn ("((" + p.CSType + ")args.Args[" + (idx - 1) + "])") + ";\n"; + } + return finish; + } + + public void GenArgsCleanup (StreamWriter sw, string finish) + { + if (retval.IsVoid && finish.Length == 0) + return; + + sw.WriteLine("\n\t\t\ttry {"); + sw.Write (finish); + if (!retval.IsVoid) { + if (retval.CSType == "bool") { + sw.WriteLine ("\t\t\t\tif (args.RetVal == null)"); + sw.WriteLine ("\t\t\t\t\treturn false;"); + } + sw.WriteLine("\t\t\t\treturn " + SymbolTable.Table.ToNativeReturn (retval.CType, "((" + retval.CSType + ")args.RetVal)") + ";"); + } + sw.WriteLine("\t\t\t} catch (Exception) {"); + sw.WriteLine ("\t\t\t\tException ex = new Exception (\"args.RetVal or 'out' property unset or set to incorrect type in " + EventHandlerQualifiedName + " callback\");"); + sw.WriteLine("\t\t\t\tGLib.ExceptionManager.RaiseUnhandledException (ex, true);"); + + sw.WriteLine ("\t\t\t\t// NOTREACHED: above call doesn't return."); + sw.WriteLine ("\t\t\t\tthrow ex;"); + sw.WriteLine("\t\t\t}"); + } + + public void GenCallback (StreamWriter sw) + { + if (IsEventHandler) + return; + + string native_signature = "IntPtr inst"; + if (parms.Count > 0) + native_signature += ", " + CallbackSig; + native_signature += ", IntPtr gch"; + + sw.WriteLine ("\t\t[GLib.CDeclCallback]"); + sw.WriteLine ("\t\tdelegate {0} {1} ({2});", retval.ToNativeType, DelegateName, native_signature); + sw.WriteLine (); + sw.WriteLine ("\t\tstatic {0} {1} ({2})", retval.ToNativeType, CallbackName, native_signature); + sw.WriteLine("\t\t{"); + sw.WriteLine("\t\t\t{0} args = new {0} ();", EventArgsQualifiedName); + sw.WriteLine("\t\t\ttry {"); + sw.WriteLine("\t\t\t\tGLib.Signal sig = ((GCHandle) gch).Target as GLib.Signal;"); + sw.WriteLine("\t\t\t\tif (sig == null)"); + sw.WriteLine("\t\t\t\t\tthrow new Exception(\"Unknown signal GC handle received \" + gch);"); + sw.WriteLine(); + string finish = GenArgsInitialization (sw); + sw.WriteLine("\t\t\t\t{0} handler = ({0}) sig.Handler;", EventHandlerQualifiedName); + sw.WriteLine("\t\t\t\thandler (GLib.Object.GetObject (inst), args);"); + sw.WriteLine("\t\t\t} catch (Exception e) {"); + sw.WriteLine("\t\t\t\tGLib.ExceptionManager.RaiseUnhandledException (e, false);"); + sw.WriteLine("\t\t\t}"); + GenArgsCleanup (sw, finish); + sw.WriteLine("\t\t}"); + sw.WriteLine(); + } + + private bool NeedNew (ObjectBase implementor) + { + return elem.HasAttribute ("new_flag") || + (container_type != null && container_type.GetSignalRecursively (Name) != null) || + (implementor != null && implementor.GetSignalRecursively (Name) != null); + } + + public void GenEventHandler (GenerationInfo gen_info) + { + if (IsEventHandler) + return; + + string ns = container_type.NS; + + StreamWriter sw = gen_info.OpenStream (EventHandlerName); + + sw.WriteLine ("namespace " + ns + " {"); + sw.WriteLine (); + sw.WriteLine ("\tusing System;"); + + sw.WriteLine (); + sw.WriteLine ("\tpublic delegate void " + EventHandlerName + "(object o, " + EventArgsName + " args);"); + sw.WriteLine (); + sw.WriteLine ("\tpublic class " + EventArgsName + " : GLib.SignalArgs {"); + for (int i = 0; i < parms.Count; i++) { + sw.WriteLine ("\t\tpublic " + parms[i].CSType + " " + parms[i].StudlyName + "{"); + if (parms[i].PassAs != "out") { + sw.WriteLine ("\t\t\tget {"); + sw.WriteLine ("\t\t\t\treturn (" + parms[i].CSType + ") Args[" + i + "];"); + sw.WriteLine ("\t\t\t}"); + } + if (parms[i].PassAs != "") { + sw.WriteLine ("\t\t\tset {"); + sw.WriteLine ("\t\t\t\tArgs[" + i + "] = (" + parms[i].CSType + ")value;"); + sw.WriteLine ("\t\t\t}"); + } + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + sw.WriteLine ("\t}"); + sw.WriteLine ("}"); + sw.Close (); + } + + public void GenEvent (StreamWriter sw, ObjectBase implementor, string target) + { + string args_type = IsEventHandler ? "" : ", typeof (" + EventArgsQualifiedName + ")"; + + if (Marshaled) { + GenCallback (sw); + args_type = ", new " + DelegateName + "(" + CallbackName + ")"; + } + + 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\tGLib.Signal sig = GLib.Signal.Lookup (" + target + ", " + CName + args_type + ");"); + sw.WriteLine("\t\t\t\tsig.AddDelegate (value);"); + sw.WriteLine("\t\t\t}"); + sw.WriteLine("\t\t\tremove {"); + sw.WriteLine("\t\t\t\tGLib.Signal sig = GLib.Signal.Lookup (" + target + ", " + CName + args_type + ");"); + sw.WriteLine("\t\t\t\tsig.RemoveDelegate (value);"); + sw.WriteLine("\t\t\t}"); + sw.WriteLine("\t\t}"); + sw.WriteLine(); + } + + public void Generate (GenerationInfo gen_info, ObjectBase implementor) + { + StreamWriter sw = gen_info.Writer; + + if (implementor == null) + GenEventHandler (gen_info); + + GenEvent (sw, implementor, "this"); + + Statistics.SignalCount++; + } + } +} + diff --git a/generator/Signature.cs b/generator/Signature.cs new file mode 100644 index 0000000000..1b0123424f --- /dev/null +++ b/generator/Signature.cs @@ -0,0 +1,123 @@ +// GtkSharp.Generation.Signature.cs - The Signature Generation Class. +// +// Author: Mike Kestner +// +// Copyright (c) 2003-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.Collections; + using System.Xml; + + public class Signature { + + private ArrayList parms = new ArrayList (); + + public Signature (Parameters parms) + { + foreach (Parameter p in parms) { + if (!parms.IsHidden (p)) + this.parms.Add (p); + } + } + + public override string ToString () + { + if (parms.Count == 0) + return ""; + + string[] result = new string [parms.Count]; + int i = 0; + + foreach (Parameter p in parms) { + result [i] = p.PassAs != "" ? p.PassAs + " " : ""; + result [i++] += p.CSType + " " + p.Name; + } + + return String.Join (", ", result); + } + + public string Types { + get { + if (parms.Count == 0) + return ""; + + string[] result = new string [parms.Count]; + int i = 0; + + foreach (Parameter p in parms) + result [i++] = p.CSType; + + return String.Join (":", result); + } + } + + public bool IsAccessor { + get { + int count = 0; + foreach (Parameter p in parms) { + if (p.PassAs == "out") + count++; + + if (count > 1) + return false; + } + return count == 1; + } + } + + public string AccessorType { + get { + foreach (Parameter p in parms) + if (p.PassAs == "out") + return p.CSType; + + return null; + } + } + + public string AccessorName { + get { + foreach (Parameter p in parms) + if (p.PassAs == "out") + return p.Name; + + return null; + } + } + + public string AsAccessor { + get { + string[] result = new string [parms.Count - 1]; + int i = 0; + + foreach (Parameter p in parms) { + if (p.PassAs == "out") + continue; + + result [i] = p.PassAs != "" ? p.PassAs + " " : ""; + result [i++] += p.CSType + " " + p.Name; + } + + return String.Join (", ", result); + } + } + } +} + diff --git a/generator/SimpleBase.cs b/generator/SimpleBase.cs new file mode 100644 index 0000000000..38bfbe36ba --- /dev/null +++ b/generator/SimpleBase.cs @@ -0,0 +1,121 @@ +// GtkSharp.Generation.SimpleBase.cs - base class for marshaling non-generated types. +// +// Author: 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; + + public abstract class SimpleBase : IGeneratable { + + string type; + string ctype; + string ns = String.Empty; + string default_value = String.Empty; + + public SimpleBase (string ctype, string type, string default_value) + { + string[] toks = type.Split('.'); + this.ctype = ctype; + this.type = toks[toks.Length - 1]; + if (toks.Length > 2) + this.ns = String.Join (".", toks, 0, toks.Length - 1); + else if (toks.Length == 2) + this.ns = toks[0]; + this.default_value = default_value; + } + + public string CName { + get { + return ctype; + } + } + + public string Name { + get { + return type; + } + } + + public string QualifiedName { + get { + return ns == String.Empty ? type : ns + "." + type; + } + } + + public virtual string MarshalType { + get { + return QualifiedName; + } + } + + public virtual string MarshalReturnType { + get { + return MarshalType; + } + } + + public virtual string DefaultValue { + get { + return default_value; + } + } + + public virtual string ToNativeReturnType { + get { + return MarshalType; + } + } + + public virtual string CallByName (string var) + { + return var; + } + + public virtual string FromNative(string var) + { + return var; + } + + public virtual string FromNativeReturn(string var) + { + return FromNative (var); + } + + public virtual string ToNativeReturn(string var) + { + return CallByName (var); + } + + public bool Validate () + { + return true; + } + + public void Generate () + { + } + + public void Generate (GenerationInfo gen_info) + { + } + } +} + diff --git a/generator/SimpleGen.cs b/generator/SimpleGen.cs new file mode 100644 index 0000000000..b382135360 --- /dev/null +++ b/generator/SimpleGen.cs @@ -0,0 +1,31 @@ +// GtkSharp.Generation.SimpleGen.cs - The Simple type Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2003 Mike Kestner +// +// 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; + + public class SimpleGen : SimpleBase { + public SimpleGen (string ctype, string type, string default_value) : base (ctype, type, default_value) {} + + } +} + diff --git a/generator/Statistics.cs b/generator/Statistics.cs new file mode 100644 index 0000000000..45457657a0 --- /dev/null +++ b/generator/Statistics.cs @@ -0,0 +1,197 @@ +// Statistics.cs : Generation statistics class implementation +// +// Author: Mike Kestner +// +// Copyright (c) 2002 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.Collections; + + public class Statistics { + + static int cbs = 0; + static int enums = 0; + static int objects = 0; + static int structs = 0; + static int boxed = 0; + static int opaques = 0; + static int interfaces = 0; + static int methods = 0; + static int ctors = 0; + static int props = 0; + static int sigs = 0; + static int throttled = 0; + static int ignored = 0; + static bool vm_ignored = false; + + public static int CBCount { + get { + return cbs; + } + set { + cbs = value; + } + } + + public static int EnumCount { + get { + return enums; + } + set { + enums = value; + } + } + + public static int ObjectCount { + get { + return objects; + } + set { + objects = value; + } + } + + public static int StructCount { + get { + return structs; + } + set { + structs = value; + } + } + + public static int BoxedCount { + get { + return boxed; + } + set { + boxed = value; + } + } + + public static int OpaqueCount { + get { + return opaques; + } + set { + opaques = value; + } + } + + public static int CtorCount { + get { + return ctors; + } + set { + ctors = value; + } + } + + public static int MethodCount { + get { + return methods; + } + set { + methods = value; + } + } + + public static int PropCount { + get { + return props; + } + set { + props = value; + } + } + + public static int SignalCount { + get { + return sigs; + } + set { + sigs = value; + } + } + + public static int IFaceCount { + get { + return interfaces; + } + set { + interfaces = value; + } + } + + public static int ThrottledCount { + get { + return throttled; + } + set { + throttled = value; + } + } + + public static int IgnoreCount { + get { + return ignored; + } + set { + ignored = value; + } + } + + public static bool VMIgnored { + get { + return vm_ignored; + } + set { + if (value) + vm_ignored = value; + } + } + + public static void Report() + { + if (VMIgnored) { + Console.WriteLine(); + Console.WriteLine("Warning: Generation throttled for Virtual Methods."); + Console.WriteLine(" Consider regenerating with --gluelib-name and --glue-filename."); + } + Console.WriteLine(); + Console.WriteLine("Generation Summary:"); + Console.Write(" Enums: " + enums); + Console.Write(" Structs: " + structs); + Console.Write(" Boxed: " + boxed); + Console.Write(" Opaques: " + opaques); + Console.Write(" Interfaces: " + interfaces); + Console.Write(" Objects: " + objects); + Console.WriteLine(" Callbacks: " + cbs); + Console.Write(" Properties: " + props); + Console.Write(" Signals: " + sigs); + Console.Write(" Methods: " + methods); + Console.Write(" Constructors: " + ctors); + Console.WriteLine(" Throttled: " + throttled); + Console.WriteLine("Total Nodes: " + (enums+structs+boxed+opaques+interfaces+cbs+objects+props+sigs+methods+ctors+throttled)); + Console.WriteLine(); + } + } +} diff --git a/generator/StructBase.cs b/generator/StructBase.cs new file mode 100644 index 0000000000..7e1b87aa0c --- /dev/null +++ b/generator/StructBase.cs @@ -0,0 +1,230 @@ +// GtkSharp.Generation.StructBase.cs - The Structure/Boxed Base Class. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// +// 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.Collections; + using System.IO; + using System.Text.RegularExpressions; + using System.Xml; + + public abstract class StructBase : ClassBase, IManualMarshaler { + + new ArrayList fields = new ArrayList (); + bool need_read_native = false; + + protected StructBase (XmlElement ns, XmlElement elem) : base (ns, elem) + { + foreach (XmlNode node in elem.ChildNodes) { + + if (!(node is XmlElement)) continue; + XmlElement member = (XmlElement) node; + + switch (node.Name) { + case "field": + fields.Add (new StructField (member, this)); + break; + + case "callback": + Statistics.IgnoreCount++; + break; + + default: + if (!IsNodeNameHandled (node.Name)) + Console.WriteLine ("Unexpected node " + node.Name + " in " + CName); + break; + } + } + } + + public override string DefaultValue { + get { + return QualifiedName + ".Zero"; + } + } + + public override string MarshalType { + get { + return "IntPtr"; + } + } + + public override string AssignToName { + get { throw new NotImplementedException (); } + } + + public override string CallByName () + { + return "this_as_native"; + } + + public override string CallByName (string var) + { + return var + "_as_native"; + } + + public override string FromNative (string var) + { + if (DisableNew) + return var + " == IntPtr.Zero ? " + QualifiedName + ".Zero : (" + QualifiedName + ") System.Runtime.InteropServices.Marshal.PtrToStructure (" + var + ", typeof (" + QualifiedName + "))"; + else + return QualifiedName + ".New (" + var + ")"; + } + + public string AllocNative (string var) + { + return "GLib.Marshaller.StructureToPtrAlloc (" + var + ")"; + } + + public string ReleaseNative (string var) + { + return "Marshal.FreeHGlobal (" +var + ")"; + } + + private bool DisableNew { + get { + return Elem.HasAttribute ("disable_new"); + } + } + + protected new void GenFields (GenerationInfo gen_info) + { + int bitfields = 0; + bool need_field = true; + + foreach (StructField field in fields) { + if (field.IsBitfield) { + if (need_field) { + StreamWriter sw = gen_info.Writer; + + sw.WriteLine ("\t\tprivate uint _bitfield{0};\n", bitfields++); + need_field = false; + } + } else + need_field = true; + field.Generate (gen_info, "\t\t"); + } + } + + public override bool Validate () + { + foreach (StructField field in fields) { + if (!field.Validate ()) { + Console.WriteLine ("in Struct " + QualifiedName); + if (!field.IsPointer) + return false; + } + } + + return base.Validate (); + } + + public override void Generate (GenerationInfo gen_info) + { + bool need_close = false; + if (gen_info.Writer == null) { + gen_info.Writer = gen_info.OpenStream (Name); + need_close = true; + } + + StreamWriter sw = gen_info.Writer; + + sw.WriteLine ("namespace " + NS + " {"); + sw.WriteLine (); + sw.WriteLine ("\tusing System;"); + sw.WriteLine ("\tusing System.Collections;"); + sw.WriteLine ("\tusing System.Runtime.InteropServices;"); + sw.WriteLine (); + + sw.WriteLine ("#region Autogenerated code"); + if (IsDeprecated) + sw.WriteLine ("\t[Obsolete]"); + sw.WriteLine ("\t[StructLayout(LayoutKind.Sequential)]"); + string access = IsInternal ? "internal" : "public"; + sw.WriteLine ("\t" + access + " struct " + Name + " {"); + sw.WriteLine (); + + need_read_native = false; + GenFields (gen_info); + sw.WriteLine (); + GenCtors (gen_info); + GenMethods (gen_info, null, this); + if (need_read_native) + GenReadNative (sw); + + if (!need_close) + return; + + sw.WriteLine ("#endregion"); + AppendCustom(sw, gen_info.CustomDir); + + sw.WriteLine ("\t}"); + sw.WriteLine ("}"); + sw.Close (); + gen_info.Writer = null; + } + + protected override void GenCtors (GenerationInfo gen_info) + { + StreamWriter sw = gen_info.Writer; + + sw.WriteLine ("\t\tpublic static {0} Zero = new {0} ();", QualifiedName); + sw.WriteLine(); + if (!DisableNew) { + sw.WriteLine ("\t\tpublic static " + QualifiedName + " New(IntPtr raw) {"); + sw.WriteLine ("\t\t\tif (raw == IntPtr.Zero)"); + sw.WriteLine ("\t\t\t\treturn {0}.Zero;", QualifiedName); + sw.WriteLine ("\t\t\treturn ({0}) Marshal.PtrToStructure (raw, typeof ({0}));", QualifiedName); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + foreach (Ctor ctor in Ctors) + ctor.IsStatic = true; + + base.GenCtors (gen_info); + } + + void GenReadNative (StreamWriter sw) + { + sw.WriteLine ("\t\tstatic void ReadNative (IntPtr native, ref {0} target)", QualifiedName); + sw.WriteLine ("\t\t{"); + sw.WriteLine ("\t\t\ttarget = New (native);"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + public override void Prepare (StreamWriter sw, string indent) + { + sw.WriteLine (indent + "IntPtr this_as_native = System.Runtime.InteropServices.Marshal.AllocHGlobal (System.Runtime.InteropServices.Marshal.SizeOf (this));"); + sw.WriteLine (indent + "System.Runtime.InteropServices.Marshal.StructureToPtr (this, this_as_native, false);"); + } + + public override void Finish (StreamWriter sw, string indent) + { + need_read_native = true; + sw.WriteLine (indent + "ReadNative (this_as_native, ref this);"); + sw.WriteLine (indent + "System.Runtime.InteropServices.Marshal.FreeHGlobal (this_as_native);"); + } + } +} + diff --git a/generator/StructField.cs b/generator/StructField.cs new file mode 100644 index 0000000000..58f92d494f --- /dev/null +++ b/generator/StructField.cs @@ -0,0 +1,149 @@ +// GtkSharp.Generation.StructField.cs - The Structure Field generation +// Class. +// +// Author: Mike Kestner +// +// Copyright (c) 2004-2005 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 StructField : FieldBase { + + public static int bitfields; + + public StructField (XmlElement elem, ClassBase container_type) : base (elem, container_type) {} + + protected override string DefaultAccess { + get { + if (IsPadding) + return "private"; + + return "public"; + } + } + + int ArrayLength { + get { + if (!IsArray) + return 0; + + int result; + try { + result = Int32.Parse (elem.GetAttribute("array_len")); + } catch (Exception) { + Console.Write ("Non-numeric array_len: " + elem.GetAttribute("array_len")); + Console.WriteLine (" warning: array field {0} incorrectly generated", Name); + result = 0; + } + return result; + } + } + + public new string CSType { + get { + string type = base.CSType; + if (IsArray) + type += "[]"; + else if ((IsPointer || SymbolTable.Table.IsOpaque (CType)) && type != "string") + type = "IntPtr"; + + return type; + } + } + + bool IsPadding { + get { + return (CName.StartsWith ("dummy") || CName.StartsWith ("padding")); + } + } + + public bool IsPointer { + get { + return (CType.EndsWith ("*") || CType.EndsWith ("pointer")); + } + } + + public new string Name { + get { + string result = ""; + if ((IsPointer || SymbolTable.Table.IsOpaque (CType)) && CSType != "string") + result = "_"; + result += SymbolTable.Table.MangleName (CName); + + return result; + } + } + + string StudlyName { + get { + string studly = base.Name; + if (studly == "") + throw new Exception ("API file must be regenerated with a current version of the GAPI parser. It is incompatible with this version of the GAPI code generator."); + + return studly; + } + } + + public override void Generate (GenerationInfo gen_info, string indent) + { + if (Hidden) + return; + + StreamWriter sw = gen_info.Writer; + SymbolTable table = SymbolTable.Table; + + string wrapped = table.GetCSType (CType); + string wrapped_name = SymbolTable.Table.MangleName (CName); + IGeneratable gen = table [CType]; + + if (IsArray) { + sw.WriteLine (indent + "[MarshalAs (UnmanagedType.ByValArray, SizeConst=" + ArrayLength + ")]"); + sw.WriteLine (indent + "{0} {1} {2};", Access, CSType, StudlyName); + } else if (IsBitfield) { + base.Generate (gen_info, indent); + } else if (gen is IAccessor) { + sw.WriteLine (indent + "private {0} {1};", gen.MarshalType, Name); + + if (Access != "private") { + IAccessor acc = table [CType] as IAccessor; + sw.WriteLine (indent + Access + " " + wrapped + " " + StudlyName + " {"); + acc.WriteAccessors (sw, indent + "\t", Name); + sw.WriteLine (indent + "}"); + } + } else if (IsPointer && (gen is StructGen || gen is BoxedGen)) { + sw.WriteLine (indent + "private {0} {1};", CSType, Name); + sw.WriteLine (); + if (Access != "private") { + sw.WriteLine (indent + Access + " " + wrapped + " " + wrapped_name + " {"); + sw.WriteLine (indent + "\tget { return " + table.FromNativeReturn (CType, Name) + "; }"); + sw.WriteLine (indent + "}"); + } + } else if (IsPointer && CSType != "string") { + // FIXME: probably some fields here which should be visible. + sw.WriteLine (indent + "private {0} {1};", CSType, Name); + } else { + sw.WriteLine (indent + "{0} {1} {2};", Access, CSType, Access == "public" ? StudlyName : Name); + } + } + } +} + diff --git a/generator/StructGen.cs b/generator/StructGen.cs new file mode 100644 index 0000000000..4d615ad158 --- /dev/null +++ b/generator/StructGen.cs @@ -0,0 +1,53 @@ +// GtkSharp.Generation.StructGen.cs - The Structure Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2001 Mike Kestner +// +// 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 StructGen : StructBase { + + public StructGen (XmlElement ns, XmlElement elem) : base (ns, elem) {} + + public override void Generate (GenerationInfo gen_info) + { + gen_info.CurrentType = Name; + + StreamWriter sw = gen_info.Writer = gen_info.OpenStream (Name); + base.Generate (gen_info); + if (GetMethod ("GetType") == null && GetMethod ("GetGType") == null) { + sw.WriteLine ("\t\tprivate static GLib.GType GType {"); + sw.WriteLine ("\t\t\tget { return GLib.GType.Pointer; }"); + sw.WriteLine ("\t\t}"); + } + sw.WriteLine ("#endregion"); + AppendCustom (sw, gen_info.CustomDir); + sw.WriteLine ("\t}"); + sw.WriteLine ("}"); + sw.Close (); + gen_info.Writer = null; + Statistics.StructCount++; + } + } +} + diff --git a/generator/SymbolTable.cs b/generator/SymbolTable.cs new file mode 100644 index 0000000000..4fc0a87114 --- /dev/null +++ b/generator/SymbolTable.cs @@ -0,0 +1,413 @@ +// GtkSharp.Generation.SymbolTable.cs - The Symbol Table Class. +// +// Author: Mike Kestner +// +// Copyright (c) 2001-2003 Mike Kestner +// Copyright (c) 2004-2005 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.Collections; + + public class SymbolTable { + + static SymbolTable table = null; + + Hashtable types = new Hashtable (); + + public static SymbolTable Table { + get { + if (table == null) + table = new SymbolTable (); + + return table; + } + } + + public SymbolTable () + { + // Simple easily mapped types + AddType (new SimpleGen ("void", "void", String.Empty)); + AddType (new SimpleGen ("gpointer", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("AtkFunction", "IntPtr", "IntPtr.Zero")); // function definition used for padding + AddType (new SimpleGen ("gboolean", "bool", "false")); + AddType (new SimpleGen ("gint", "int", "0")); + AddType (new SimpleGen ("guint", "uint", "0")); + AddType (new SimpleGen ("int", "int", "0")); + AddType (new SimpleGen ("unsigned", "uint", "0")); + AddType (new SimpleGen ("unsigned int", "uint", "0")); + AddType (new SimpleGen ("unsigned-int", "uint", "0")); + AddType (new SimpleGen ("gshort", "short", "0")); + AddType (new SimpleGen ("gushort", "ushort", "0")); + AddType (new SimpleGen ("short", "short", "0")); + AddType (new SimpleGen ("guchar", "byte", "0")); + AddType (new SimpleGen ("unsigned char", "byte", "0")); + AddType (new SimpleGen ("unsigned-char", "byte", "0")); + AddType (new SimpleGen ("guint1", "bool", "false")); + AddType (new SimpleGen ("uint1", "bool", "false")); + AddType (new SimpleGen ("gint8", "sbyte", "0")); + AddType (new SimpleGen ("guint8", "byte", "0")); + AddType (new SimpleGen ("gint16", "short", "0")); + AddType (new SimpleGen ("guint16", "ushort", "0")); + AddType (new SimpleGen ("gint32", "int", "0")); + AddType (new SimpleGen ("guint32", "uint", "0")); + AddType (new SimpleGen ("gint64", "long", "0")); + AddType (new SimpleGen ("guint64", "ulong", "0")); + AddType (new SimpleGen ("long long", "long", "0")); + AddType (new SimpleGen ("gfloat", "float", "0.0")); + AddType (new SimpleGen ("float", "float", "0.0")); + AddType (new SimpleGen ("gdouble", "double", "0.0")); + AddType (new SimpleGen ("double", "double", "0.0")); + AddType (new SimpleGen ("goffset", "long", "0")); + AddType (new SimpleGen ("GQuark", "int", "0")); + + // platform specific integer types. +#if WIN64LONGS + AddType (new SimpleGen ("long", "int", "0")); + AddType (new SimpleGen ("glong", "int", "0")); + AddType (new SimpleGen ("ulong", "uint", "0")); + AddType (new SimpleGen ("gulong", "uint", "0")); + AddType (new SimpleGen ("unsigned long", "uint", "0")); +#else + AddType (new LPGen ("long")); + AddType (new LPGen ("glong")); + AddType (new LPUGen ("ulong")); + AddType (new LPUGen ("gulong")); + AddType (new LPUGen ("unsigned long")); +#endif + + AddType (new LPGen ("ssize_t")); + AddType (new LPGen ("gssize")); + AddType (new LPUGen ("size_t")); + AddType (new LPUGen ("gsize")); + +#if OFF_T_8 + AddType (new AliasGen ("off_t", "long")); +#else + AddType (new LPGen ("off_t")); +#endif + + // string types + AddType (new ConstStringGen ("const-gchar")); + AddType (new ConstStringGen ("const-xmlChar")); + AddType (new ConstStringGen ("const-char")); + AddType (new ConstFilenameGen ("const-gfilename")); + AddType (new MarshalGen ("gfilename", "string", "IntPtr", "GLib.Marshaller.StringToFilenamePtr({0})", "GLib.Marshaller.FilenamePtrToStringGFree({0})")); + AddType (new MarshalGen ("gchar", "string", "IntPtr", "GLib.Marshaller.StringToPtrGStrdup({0})", "GLib.Marshaller.PtrToStringGFree({0})")); + AddType (new MarshalGen ("char", "string", "IntPtr", "GLib.Marshaller.StringToPtrGStrdup({0})", "GLib.Marshaller.PtrToStringGFree({0})")); + AddType (new SimpleGen ("GStrv", "string[]", "null")); + + // manually wrapped types requiring more complex marshaling + AddType (new ManualGen ("GInitiallyUnowned", "GLib.InitiallyUnowned", "GLib.Object.GetObject ({0})")); + AddType (new ManualGen ("GObject", "GLib.Object", "GLib.Object.GetObject ({0})")); + AddType (new ManualGen ("GList", "GLib.List")); + AddType (new ManualGen ("GPtrArray", "GLib.PtrArray")); + AddType (new ManualGen ("GSList", "GLib.SList")); + AddType (new MarshalGen ("gunichar", "char", "uint", "GLib.Marshaller.CharToGUnichar ({0})", "GLib.Marshaller.GUnicharToChar ({0})")); + AddType (new MarshalGen ("time_t", "System.DateTime", "IntPtr", "GLib.Marshaller.DateTimeTotime_t ({0})", "GLib.Marshaller.time_tToDateTime ({0})")); + AddType (new MarshalGen ("GString", "string", "IntPtr", "new GLib.GString ({0}).Handle", "GLib.GString.PtrToString ({0})")); + AddType (new MarshalGen ("GType", "GLib.GType", "IntPtr", "{0}.Val", "new GLib.GType({0})", "GLib.GType.None")); + AddType (new ByRefGen ("GValue", "GLib.Value")); + AddType (new SimpleGen ("GDestroyNotify", "GLib.DestroyNotify", "null")); + + // FIXME: These ought to be handled properly. + AddType (new SimpleGen ("GC", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("GError", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("GMemChunk", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("GTimeVal", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("GClosure", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("GArray", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("GByteArray", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("GData", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("GIOChannel", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("GTypeModule", "GLib.Object", "null")); + AddType (new SimpleGen ("GHashTable", "System.IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("va_list", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("GParamSpec", "IntPtr", "IntPtr.Zero")); + AddType (new SimpleGen ("gconstpointer", "IntPtr", "IntPtr.Zero")); + } + + public void AddType (IGeneratable gen) + { + types [gen.CName] = gen; + } + + public void AddTypes (IGeneratable[] gens) + { + foreach (IGeneratable gen in gens) + types [gen.CName] = gen; + } + + public int Count { + get + { + return types.Count; + } + } + + public IEnumerable Generatables { + get { + return types.Values; + } + } + + public IGeneratable this [string ctype] { + get { + return DeAlias (ctype) as IGeneratable; + } + } + + private bool IsConstString (string type) + { + switch (type) { + case "const-gchar": + case "const-char": + case "const-xmlChar": + case "const-gfilename": + return true; + default: + return false; + } + } + + private string Trim(string type) + { + // HACK: If we don't detect this here, there is no + // way of indicating it in the symbol table + if (type == "void*" || type == "const-void*") return "gpointer"; + + string trim_type = type.TrimEnd('*'); + + if (IsConstString (trim_type)) + return trim_type; + + if (trim_type.StartsWith("const-")) return trim_type.Substring(6); + return trim_type; + } + + private object DeAlias (string type) + { + type = Trim (type); + while (types [type] is AliasGen) { + IGeneratable igen = types [type] as AliasGen; + types [type] = types [igen.Name]; + type = igen.Name; + } + + return types [type]; + } + + public string FromNativeReturn(string c_type, string val) + { + IGeneratable gen = this[c_type]; + if (gen == null) + return ""; + return gen.FromNativeReturn (val); + } + + public string ToNativeReturn(string c_type, string val) + { + IGeneratable gen = this[c_type]; + if (gen == null) + return ""; + return gen.ToNativeReturn (val); + } + + public string FromNative(string c_type, string val) + { + IGeneratable gen = this[c_type]; + if (gen == null) + return ""; + return gen.FromNative (val); + } + + public string GetCSType(string c_type) + { + IGeneratable gen = this[c_type]; + if (gen == null) + return ""; + return gen.QualifiedName; + } + + public string GetName(string c_type) + { + IGeneratable gen = this[c_type]; + if (gen == null) + return ""; + return gen.Name; + } + + public string GetMarshalReturnType(string c_type) + { + IGeneratable gen = this[c_type]; + if (gen == null) + return ""; + return gen.MarshalReturnType; + } + + public string GetToNativeReturnType(string c_type) + { + IGeneratable gen = this[c_type]; + if (gen == null) + return ""; + return gen.ToNativeReturnType; + } + + public string GetMarshalType(string c_type) + { + IGeneratable gen = this[c_type]; + if (gen == null) + return ""; + return gen.MarshalType; + } + + public string CallByName(string c_type, string var_name) + { + IGeneratable gen = this[c_type]; + if (gen == null) + return ""; + return gen.CallByName(var_name); + } + + public bool IsOpaque(string c_type) + { + if (this[c_type] is OpaqueGen) + return true; + + return false; + } + + public bool IsBoxed(string c_type) + { + if (this[c_type] is BoxedGen) + return true; + + return false; + } + + public bool IsStruct(string c_type) + { + if (this[c_type] is StructGen) + return true; + + return false; + } + + public bool IsEnum(string c_type) + { + if (this[c_type] is EnumGen) + return true; + + return false; + } + + public bool IsEnumFlags(string c_type) + { + EnumGen gen = this [c_type] as EnumGen; + return (gen != null && gen.Elem.GetAttribute ("type") == "flags"); + } + + public bool IsInterface(string c_type) + { + if (this[c_type] is InterfaceGen) + return true; + + return false; + } + + public ClassBase GetClassGen(string c_type) + { + return this[c_type] as ClassBase; + } + + public bool IsObject(string c_type) + { + if (this[c_type] is ObjectGen) + return true; + + return false; + } + + public bool IsCallback(string c_type) + { + if (this[c_type] is CallbackGen) + return true; + + return false; + } + + public bool IsManuallyWrapped(string c_type) + { + if (this[c_type] is ManualGen) + return true; + + return false; + } + + public string MangleName(string name) + { + switch (name) { + case "string": + return "str1ng"; + case "event": + return "evnt"; + case "null": + return "is_null"; + case "object": + return "objekt"; + case "params": + return "parms"; + case "ref": + return "reference"; + case "in": + return "in_param"; + case "out": + return "out_param"; + case "fixed": + return "mfixed"; + case "byte": + return "_byte"; + case "new": + return "_new"; + case "base": + return "_base"; + case "lock": + return "_lock"; + case "callback": + return "cb"; + case "readonly": + return "read_only"; + case "interface": + return "iface"; + case "internal": + return "_internal"; + case "where": + return "wh3r3"; + case "foreach": + return "for_each"; + case "remove": + return "_remove"; + default: + break; + } + + return name; + } + } +} diff --git a/generator/VMSignature.cs b/generator/VMSignature.cs new file mode 100644 index 0000000000..c14ce51f0c --- /dev/null +++ b/generator/VMSignature.cs @@ -0,0 +1,91 @@ +// GtkSharp.Generation.VMSignature.cs - The Virtual Method Signature Generation Class. +// +// Author: Mike Kestner +// +// Copyright (c) 2003-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.Collections; + using System.Xml; + + public class VMSignature { + + private ArrayList parms = new ArrayList (); + + public VMSignature (Parameters parms) + { + bool has_cb = parms.HideData; + for (int i = 0; i < parms.Count; i++) { + Parameter p = parms [i]; + + if (i > 0 && p.IsLength && parms [i - 1].IsString) + continue; + + if (p.IsCount && ((i > 0 && parms [i - 1].IsArray) || (i < parms.Count - 1 && parms [i + 1].IsArray))) + continue; + + has_cb = has_cb || p.Generatable is CallbackGen; + if (p.IsUserData && has_cb) + continue; + + if (p.CType == "GError**") + continue; + + if (p.Scope == "notified") + i += 2; + + this.parms.Add (p); + } + } + + public string GetCallString (bool use_place_holders) + { + if (parms.Count == 0) + return ""; + + string[] result = new string [parms.Count]; + int i = 0; + foreach (Parameter p in parms) { + result [i] = p.PassAs != "" ? p.PassAs + " " : ""; + result [i] += use_place_holders ? "{" + i + "}" : p.Name; + i++; + } + + return String.Join (", ", result); + } + + public override string ToString () + { + if (parms.Count == 0) + return ""; + + string[] result = new string [parms.Count]; + int i = 0; + + foreach (Parameter p in parms) { + result [i] = p.PassAs != "" ? p.PassAs + " " : ""; + result [i++] += p.CSType + " " + p.Name; + } + + return String.Join (", ", result); + } + } +} + diff --git a/generator/VirtualMethod.cs b/generator/VirtualMethod.cs new file mode 100644 index 0000000000..670eb24013 --- /dev/null +++ b/generator/VirtualMethod.cs @@ -0,0 +1,156 @@ +// GtkSharp.Generation.VirtualMethod.cs - The VirtualMethod Generatable. +// +// Author: Mike Kestner +// +// Copyright (c) 2003-2004 Novell, Inc. +// Copyright (c) 2009 Christian Hoff +// +// 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.Collections; + using System.IO; + using System.Xml; + + public abstract class VirtualMethod : MethodBase { + protected ReturnValue retval; + protected ManagedCallString call; + + protected string modifiers = ""; + + public VirtualMethod (XmlElement elem, ObjectBase container_type) : base (elem, container_type) + { + if (container_type.ParserVersion == 1) { + // The old pre 2.14 parser didn't drop the 1st parameter in all and elements + parms = new Parameters (elem ["parameters"], true); + } + retval = new ReturnValue (elem ["return-type"]); + } + + protected abstract string CallString { + get; + } + + VMSignature signature; + protected new VMSignature Signature { + get { + if (signature == null) + signature = new VMSignature (parms); + + return signature; + } + } + + /* Creates a callback method which invokes the corresponding virtual method + * @implementor is the class that implements the virtual method(e.g. the class that derives from an interface) or NULL if containing and declaring type are equal + */ + public void GenerateCallback (StreamWriter sw, ClassBase implementor) + { + if (!Validate ()) + return; + + string native_signature = ""; + if (!IsStatic) { + native_signature += "IntPtr inst"; + if (parms.Count > 0) + native_signature += ", "; + } + if (parms.Count > 0) + native_signature += parms.ImportSignature; + + sw.WriteLine ("\t\t[GLib.CDeclCallback]"); + sw.WriteLine ("\t\tdelegate {0} {1}NativeDelegate ({2});", retval.ToNativeType, this.Name, native_signature); + sw.WriteLine (); + sw.WriteLine ("\t\tstatic {0} {1}_cb ({2})", retval.ToNativeType, this.Name, native_signature); + sw.WriteLine ("\t\t{"); + string unconditional = call.Unconditional ("\t\t\t"); + if (unconditional.Length > 0) + sw.WriteLine (unconditional); + sw.WriteLine ("\t\t\ttry {"); + + if (!this.IsStatic) { + string type; + if (implementor != null) + type = implementor.QualifiedName; + else if (this.container_type is InterfaceGen) + type = this.container_type.Name + "Implementor"; // We are in an interface/adaptor, invoke the method in the implementor class + else + type = this.container_type.Name; + + sw.WriteLine ("\t\t\t\t{0} __obj = GLib.Object.GetObject (inst, false) as {0};", type); + } + + sw.Write (call.Setup ("\t\t\t\t")); + sw.Write ("\t\t\t\t"); + if (!retval.IsVoid) + sw.Write (retval.CSType + " __result = "); + if (!this.IsStatic) + sw.Write ("__obj."); + sw.WriteLine (this.CallString + ";"); + sw.Write (call.Finish ("\t\t\t\t")); + if (!retval.IsVoid) + sw.WriteLine ("\t\t\t\treturn " + retval.ToNative ("__result") + ";"); + + bool fatal = parms.HasOutParam || !retval.IsVoid; + sw.WriteLine ("\t\t\t} catch (Exception e) {"); + sw.WriteLine ("\t\t\t\tGLib.ExceptionManager.RaiseUnhandledException (e, " + (fatal ? "true" : "false") + ");"); + if (fatal) { + sw.WriteLine ("\t\t\t\t// NOTREACHED: above call does not return."); + sw.WriteLine ("\t\t\t\tthrow e;"); + } + sw.WriteLine ("\t\t\t}"); + sw.WriteLine ("\t\t}"); + sw.WriteLine (); + } + + public bool IsValid { + get { + return Validate (); + } + } + + enum ValidState { + Unvalidated, + Invalid, + Valid + } + + ValidState vstate = ValidState.Unvalidated; + + public override bool Validate () + { + if (vstate != ValidState.Unvalidated) + return vstate == ValidState.Valid; + + vstate = ValidState.Valid; + if (!parms.Validate () || !retval.Validate ()) { + vstate = ValidState.Invalid; + } + + if (vstate == ValidState.Invalid) { + Console.WriteLine ("(in virtual method " + container_type.QualifiedName + "." + Name + ")"); + return false; + } else { + // The call string has to be created *after* the params have been validated since the Parameters class contains no elements before validation + call = new ManagedCallString (parms); + return true; + } + } + } +} + diff --git a/generator/gst-codegen.diff b/generator/gst-codegen.diff new file mode 100644 index 0000000000..4a4baf2837 --- /dev/null +++ b/generator/gst-codegen.diff @@ -0,0 +1,24 @@ +Index: FieldBase.cs +=================================================================== +--- FieldBase.cs (Revision 134154) ++++ FieldBase.cs (Arbeitskopie) +@@ -89,7 +89,7 @@ + void CheckGlue () + { + getterName = setterName = getOffsetName = null; +- if (Access != "public") ++ if (DefaultAccess != "public" && (!elem.HasAttribute ("access") || (Access != "public" && Access != "protected" && Access != "internal"))) + return; + + string prefix = (container_type.NS + "Sharp_" + container_type.NS + "_" + container_type.Name).Replace(".", "__").ToLower (); +@@ -154,8 +154,9 @@ + StreamWriter sw = gen_info.Writer; + string modifiers = elem.HasAttribute ("new_flag") ? "new " : ""; + bool is_struct = table.IsStruct (CType) || table.IsBoxed (CType); ++ string access = elem.HasAttribute ("access") ? elem.GetAttribute ("access") : "public"; + +- sw.WriteLine (indent + "public " + modifiers + CSType + " " + Name + " {"); ++ sw.WriteLine (indent + access + " " + modifiers + CSType + " " + Name + " {"); + + if (Getter != null) { + sw.Write (indent + "\tget "); diff --git a/gstreamer-sharp/Makefile.am b/gstreamer-sharp/Makefile.am index 96d8eb7476..7de8de751d 100644 --- a/gstreamer-sharp/Makefile.am +++ b/gstreamer-sharp/Makefile.am @@ -121,8 +121,8 @@ $(API): $(srcdir)/$(RAW_API) $(srcdir)/$(METADATA) $(srcdir)/$(SYMBOLS) $(MONO) $(top_builddir)/parser/gst-gapi-fixup.exe --api=$(API) --metadata=$(srcdir)/$(METADATA) \ --symbols=$(srcdir)/$(SYMBOLS) -generated-stamp: $(API) $(GAPI_CODEGEN) $(build_customs) $(overrides) - $(GAPI_CODEGEN) --generate $(API) \ +generated-stamp: $(API) $(build_customs) $(overrides) + $(MONO) $(top_builddir)/generator/gst-gapi_codegen.exe--generate $(API) \ --outdir=generated --customdir=$(srcdir) --assembly-name=$(ASSEMBLY_NAME) \ --gluelib-name=gstreamersharpglue-0.10 --glue-filename=glue/generated.c \ --glue-includes=$(glue_includes) \