GtkSharp/generator/CallbackGen.cs
Gonzalo Paniagua Javier 3821938764 2003-04-03 Gonzalo Paniagua Javier <gonzalo@ximian.com>
* generator/CallbackGen.cs: the new generated wrappers have:
		-(optional) Field of the same type returned by the callback.
		-A call to RemoveIfNotAlive at the beginning. It returns true,
		return the dummy field.
		-Added an object to the ctor signature and pass it to the base
		class.

	* generator/Ctor.cs: added a Params property.

	* generator/Method.cs: set Static property in Parameters if the method
	is static.

	* generator/Parameters.cs: added Static property. The call creation of
	the delegate wrapper (if applicable) uses the new signature. Pass a null
	as object is the method is static.

	* generator/StructBase.cs: set Static for the parameters of the ctors.

	* glib/DelegateWrapper.cs: the ctor takes an object (the one creating
	the wrapper or null) and creates a weak reference to it. Store it in
	a static Hashtable (this way the wrapper itself is not garbage
	collected).
	(RemoveIfNotAlive): called from the native delegate callbacks. If the
	target of the weak reference has been garbage collected, removes itself
	from the hashtable to let the GC dispose this instance and returns true.

	* gdk/Pixbuf.custom:
	* gtk/Clipboard.custom:
	* gtk/GtkSharp.GtkClipboardClearFuncNative.cs:
	* gtk/GtkSharp.GtkClipboardGetFuncNative.cs:
	* glade/XML.custom: changed delegate wrappers to match the new
	signature.

svn path=/trunk/gtk-sharp/; revision=13237
2003-04-06 09:21:15 +00:00

230 lines
6.4 KiB
C#

// GtkSharp.Generation.CallbackGen.cs - The Callback Generatable.
//
// Author: Mike Kestner <mkestner@speakeasy.net>
//
// (c) 2002 Mike Kestner
namespace GtkSharp.Generation {
using System;
using System.IO;
using System.Xml;
public class CallbackGen : GenBase, IGeneratable {
private Parameters parms;
public CallbackGen (XmlElement ns, XmlElement elem) : base (ns, elem)
{
if (elem ["parameters"] != null)
parms = new Parameters (elem ["parameters"]);
}
public String MarshalType {
get
{
return NS + "Sharp." + Name + "Native";
}
}
public String MarshalReturnType {
get
{
return MarshalType;
}
}
public String CallByName (String var_name)
{
return var_name + ".NativeDelegate";
}
public String FromNative(String var)
{
return var;
}
public String FromNativeReturn(String var)
{
return FromNative (var);
}
private void GenWrapper (string s_ret, string sig)
{
char sep = Path.DirectorySeparatorChar;
string dir = ".." + sep + NS.ToLower() + sep + "generated";
if (!Directory.Exists (dir))
Directory.CreateDirectory (dir);
string wrapper = Name + "Native";
string filename = dir + sep + NS + "Sharp." + wrapper + ".cs";
FileStream stream = new FileStream (filename, FileMode.Create, FileAccess.Write);
StreamWriter sw = new StreamWriter (stream);
sw.WriteLine ("// Generated File. Do not modify.");
sw.WriteLine ("// <c> 2001-2002 Mike Kestner");
sw.WriteLine ();
sw.WriteLine ("namespace " + NS + "Sharp {");
sw.WriteLine ();
sw.WriteLine ("\tusing System;");
sw.WriteLine ();
sw.WriteLine ("#region Autogenerated code");
string import_sig;
if (parms != null)
{
parms.CreateSignature (false);
import_sig = parms.ImportSig;
} else
import_sig = "";
XmlElement ret_elem = Elem["return-type"];
string rettype = ret_elem.GetAttribute("type");
string m_ret = SymbolTable.GetMarshalReturnType (rettype);
ClassBase ret_wrapper = SymbolTable.GetClassGen (rettype);
sw.WriteLine ("\tpublic delegate " + m_ret + " " + wrapper + "(" + import_sig + ");");
sw.WriteLine ();
sw.WriteLine ("\tpublic class " + Name + "Wrapper : GLib.DelegateWrapper {");
if (m_ret != "void") {
if (SymbolTable.IsEnum (rettype)) {
sw.WriteLine ("\t\tstatic int _dummy;");
} else if (ret_wrapper != null && (ret_wrapper is ObjectGen || ret_wrapper is OpaqueGen)) {
// Do nothing
} else if (!SymbolTable.IsStruct (rettype) && !SymbolTable.IsBoxed (rettype)) {
sw.WriteLine ("\t\tstatic {0} _dummy;", s_ret);
}
}
sw.WriteLine ();
sw.WriteLine ("\t\tpublic " + m_ret + " NativeCallback (" + import_sig + ")");
sw.WriteLine ("\t\t{");
sw.Write ("\t\t\tif (RemoveIfNotAlive ()) return ");
if (SymbolTable.IsStruct (rettype) || SymbolTable.IsBoxed (rettype))
sw.WriteLine ("IntPtr.Zero;");
else if (ret_wrapper != null && (ret_wrapper is ObjectGen || ret_wrapper is OpaqueGen))
sw.WriteLine ("IntPtr.Zero;");
else
sw.WriteLine (m_ret != "void" ? "_dummy;" : ";");
int count = (parms != null) ? parms.Count : 0;
if (count > 0)
sw.WriteLine ("\t\t\tobject[] _args = new object[{0}];", count);
int idx = 0;
bool need_sep = false;
string call_str = "";
for (int i = 0; i < count; i++)
{
string parm_name = parms[i].Name;
string ctype = parms[i].CType;
if (i > 0 && parms[i].IsLength && parms[i-1].IsString)
continue;
if ((i == count - 1) && ctype == "gpointer" && (parm_name.EndsWith ("data") || parm_name.EndsWith ("data_or_owner")))
continue;
string cstype = parms[i].CSType;
// FIXME: Too much code copy/pasted here. Refactor?
ClassBase parm_wrapper = SymbolTable.GetClassGen (ctype);
sw.WriteLine("\t\t\t_args[" + idx + "] = " + SymbolTable.FromNative (ctype, parm_name) + ";");
if ((parm_wrapper != null && ((parm_wrapper is OpaqueGen))) || SymbolTable.IsManuallyWrapped (ctype)) {
sw.WriteLine("\t\t\tif (_args[" + idx + "] == null)");
sw.WriteLine("\t\t\t\t_args[{0}] = new {1}({2});", idx, cstype, parm_name);
}
if (need_sep)
call_str += ", ";
else
need_sep = true;
call_str += String.Format ("({0}) _args[{1}]", cstype, idx);
idx++;
}
sw.Write ("\t\t\t");
string invoke = "_managed (" + call_str + ")";
if (m_ret != "void") {
if (ret_wrapper != null && (ret_wrapper is ObjectGen || ret_wrapper is OpaqueGen))
sw.WriteLine ("return (({0}) {1}).Handle;", s_ret, invoke);
else if (SymbolTable.IsStruct (rettype) || SymbolTable.IsBoxed (rettype)) {
// Shoot. I have no idea what to do here.
sw.WriteLine ("return IntPtr.Zero;");
}
else if (SymbolTable.IsEnum (rettype))
sw.WriteLine ("return (int) {0};", invoke);
else
sw.WriteLine ("return ({0}) {1};", s_ret, invoke);
}
else
sw.WriteLine (invoke + ";");
sw.WriteLine ("\t\t}");
sw.WriteLine ();
sw.WriteLine ("\t\tpublic {0} NativeDelegate;", wrapper);
sw.WriteLine ("\t\tprotected {0} _managed;", NS + "." + Name);
sw.WriteLine ();
sw.WriteLine ("\t\tpublic {0} ({1} managed, object o) : base (o)", Name + "Wrapper", NS + "." + Name);
sw.WriteLine ("\t\t{");
sw.WriteLine ("\t\t\tNativeDelegate = new {0} (NativeCallback);", wrapper);
sw.WriteLine ("\t\t\t_managed = managed;");
sw.WriteLine ("\t\t}");
sw.WriteLine ("\t}");
sw.WriteLine ("#endregion");
CloseWriter (sw);
}
public void Generate ()
{
if (!DoGenerate)
return;
XmlElement ret_elem = Elem["return-type"];
if (ret_elem == null) {
Console.WriteLine("No return type in callback " + CName);
Statistics.ThrottledCount++;
return;
}
string rettype = ret_elem.GetAttribute("type");
string s_ret = SymbolTable.GetCSType (rettype);
if (s_ret == "") {
Console.WriteLine("rettype: " + rettype + " in callback " + CName);
Statistics.ThrottledCount++;
return;
}
if ((parms != null) && !parms.Validate ()) {
Console.WriteLine(" in callback " + CName + " **** Stubbing it out ****");
Statistics.ThrottledCount++;
parms = null;
}
StreamWriter sw = CreateWriter ();
string sig = "";
if (parms != null) {
parms.HideData = true;
parms.CreateSignature (false);
sig = parms.Signature;
}
sw.WriteLine ("\tpublic delegate " + s_ret + " " + Name + "(" + sig + ");");
CloseWriter (sw);
GenWrapper (s_ret, sig);
Statistics.CBCount++;
}
}
}