diff --git a/generator/GObjectVM.cs b/generator/GObjectVM.cs index 07dc2f43d..1d62a4ba9 100644 --- a/generator/GObjectVM.cs +++ b/generator/GObjectVM.cs @@ -187,9 +187,26 @@ protected void GenerateMethodBody (StreamWriter sw, ClassBase implementor) 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 ()); + string ret, signature; + if (IsAccessor) { + ret = Signature.AccessorType; + signature = Signature.AsAccessor; + } else { + ret = retval.CSType; + signature = Signature.ToString (); + } + + sw.WriteLine ("virtual {0} On{1} ({2})", ret, this.Name, signature); sw.WriteLine ("\t\t{"); + var accessorParamName = Signature.AccessorName; + if (IsAccessor) { + sw.WriteLine ("\t\t\t{0} {1};", ret, accessorParamName); + } + sw.WriteLine ("\t\t\t{0}Internal{1} ({2});", retval.IsVoid ? "" : "return ", this.Name, Signature.GetCallString (false)); + if (IsAccessor) { + sw.WriteLine ("\t\t\treturn {0};", accessorParamName); + } sw.WriteLine ("\t\t}"); sw.WriteLine (); // This method is to be invoked from existing VM implementations in the custom code diff --git a/generator/InterfaceVM.cs b/generator/InterfaceVM.cs index 39308c09a..bcc4a84d7 100644 --- a/generator/InterfaceVM.cs +++ b/generator/InterfaceVM.cs @@ -81,7 +81,9 @@ public void GenerateDeclaration (StreamWriter sw, InterfaceVM complement) } } else if (IsSetter) sw.WriteLine ("\t\t" + parms[0].CSType + " " + Name.Substring (3) + " { set; }"); - else + else if (IsAccessor) { + sw.WriteLine ("\t\t" + Signature.AccessorType + " " + Name + " (" + Signature.AsAccessor + ");"); + } else sw.WriteLine ("\t\t" + retval.CSType + " " + Name + " (" + Signature + ");"); } diff --git a/generator/ManagedCallString.cs b/generator/ManagedCallString.cs index 3e54fe349..cd4f01652 100644 --- a/generator/ManagedCallString.cs +++ b/generator/ManagedCallString.cs @@ -24,6 +24,7 @@ namespace GtkSharp.Generation { using System; using System.Collections.Generic; using System.IO; + using System.Linq; public class ManagedCallString { @@ -34,9 +35,18 @@ public class ManagedCallString { string destroy_param = null; public ManagedCallString (Parameters parms) + : this (parms, false) + { + } + + private ManagedCallString (Parameters parms, bool stripAccessorParameter) { for (int i = 0; i < parms.Count; i ++) { Parameter p = parms [i]; + if (stripAccessorParameter && p.PassAs == "out") { + continue; + } + if (p.IsLength && i > 0 && parms [i-1].IsString) continue; else if (p.Scope == "notified") { @@ -90,6 +100,14 @@ public string Unconditional (string indent) { return ret; } + public static ManagedCallString CreateWithoutAccessorParameter (Parameters parms, + out Parameter accessorParam) + { + var call = new ManagedCallString (parms, true); + accessorParam = parms.FirstOrDefault (p => p.PassAs == "out"); + return call; + } + public string Setup (string indent) { string ret = ""; @@ -158,21 +176,29 @@ public string Finish (string indent) continue; } - 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 if (igen is IManualMarshaler) - ret += String.Format ("{0}{1} = {2};", indent, p.Name, (igen as IManualMarshaler).AllocNative ("my" + p.Name)); - else - ret += indent + p.Name + " = " + igen.CallByName ("my" + p.Name) + ";\n"; + ret += GetParamAssignmentStatement ("my" + p.Name, p, indent); } return ret; } + public static string GetParamAssignmentStatement (string srcParameterName, Parameter p, string indent) + { + var ret = string.Empty; + IGeneratable igen = p.Generatable; + + if (igen is CallbackGen) + return string.Empty; + else if (igen is StructBase || igen is ByRefGen) + ret += indent + String.Format ("if ({0} != IntPtr.Zero) System.Runtime.InteropServices.Marshal.StructureToPtr ({1}, {0}, false);\n", p.Name, srcParameterName); + else if (igen is IManualMarshaler) + ret += String.Format ("{0}{1} = {2};", indent, p.Name, (igen as IManualMarshaler).AllocNative (srcParameterName)); + else + ret += indent + p.Name + " = " + igen.CallByName (srcParameterName) + ";\n"; + + return ret; + } + public string DisposeParams (string indent) { string ret = ""; diff --git a/generator/VMSignature.cs b/generator/VMSignature.cs index d2dbc7ce4..0a3b0bdf7 100644 --- a/generator/VMSignature.cs +++ b/generator/VMSignature.cs @@ -55,6 +55,57 @@ public VMSignature (Parameters parms) } } + 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); + } + } + public string GetCallString (bool use_place_holders) { if (parms.Count == 0) diff --git a/generator/VirtualMethod.cs b/generator/VirtualMethod.cs index 901ad02bd..3175cf3dd 100644 --- a/generator/VirtualMethod.cs +++ b/generator/VirtualMethod.cs @@ -30,6 +30,7 @@ namespace GtkSharp.Generation { public abstract class VirtualMethod : MethodBase { protected ReturnValue retval; protected ManagedCallString call; + private Parameter accessorParam; protected string modifiers = ""; @@ -56,6 +57,12 @@ protected abstract string CallString { } } + protected bool IsAccessor { + get { + return retval.IsVoid && Signature.IsAccessor; + } + } + /* 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 */ @@ -99,16 +106,22 @@ public void GenerateCallback (StreamWriter sw, ClassBase implementor) } string indent = "\t\t\t\t"; - if (!retval.IsVoid) + if (IsAccessor) { + sw.WriteLine (indent + Signature.AccessorType + " __result;"); + } else if (!retval.IsVoid) sw.WriteLine (indent + retval.CSType + " __result;"); sw.Write (call.Setup (indent)); sw.Write (indent); - if (!retval.IsVoid) + if (!retval.IsVoid || IsAccessor) sw.Write ("__result = "); if (!this.IsStatic) sw.Write ("__obj."); sw.WriteLine (this.CallString + ";"); sw.Write (call.Finish (indent)); + if (IsAccessor) { + sw.Write (ManagedCallString.GetParamAssignmentStatement ("__result", accessorParam, indent)); + } + if (!retval.IsVoid) sw.WriteLine ("\t\t\t\treturn " + retval.ToNative ("__result") + ";"); @@ -149,7 +162,12 @@ public override bool Validate (LogWriter log) return false; } - call = new ManagedCallString (parms); + if (IsAccessor) { + call = ManagedCallString.CreateWithoutAccessorParameter (parms, out accessorParam); + } else { + call = new ManagedCallString (parms); + } + return true; } }