GtkSharp/generator/Signal.cs
Andres G. Aragoneses 6cb03440c1 generator: generate all interfaces with the "I" prefix (.NET convention)
To be able to do this, Name property of GenBase class is now virtual, so
that it can be overriden in InterfaceGen with the new name.

Adapters, however, are still classes and then need special care as such
(cannot use the 'Name' property anymore), but this improves a bit the
readability of some parts of the code as the *Implementor and *Adapter
suffixes are now concentrated in just two new properties of GenBase and
not repeated all over the place.
2013-07-23 12:05:24 -05:00

335 lines
11 KiB
C#

// GtkSharp.Generation.Signal.cs - The Signal Generatable.
//
// Author: Mike Kestner <mkestner@speakeasy.net>
//
// 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 (LogWriter log)
{
log.Member = Name;
if (Name == "") {
log.Warn ("Nameless signal found. Add name attribute with fixup.");
Statistics.ThrottledCount++;
return false;
} else if (!parms.Validate (log) || !retval.Validate (log)) {
Statistics.ThrottledCount++;
return false;
}
return true;
}
public void GenerateDecl (StreamWriter sw)
{
if (elem.GetAttributeAsBoolean ("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 || igen is ByRefGen) && p.PassAs != "")
finish += "\t\t\t\tif (arg" + idx + " != IntPtr.Zero) System.Runtime.InteropServices.Marshal.StructureToPtr (args.Args[" + idx + "], arg" + idx + ", false);\n";
else if (igen is IManualMarshaler && p.PassAs != "")
finish += String.Format ("\t\t\t\targ{0} = {1};\n", idx, (igen as IManualMarshaler).AllocNative ("args.Args[" + idx + "]"));
else if (p.PassAs != "")
finish += "\t\t\t\targ" + idx + " = " + igen.CallByName ("((" + p.CSType + ")args.Args[" + idx + "])") + ";\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 {0};", retval.ToNative (String.Format ("(({0}) args.RetVal)", retval.CSType)));
}
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[UnmanagedFunctionPointer (CallingConvention.Cdecl)]");
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.GetAttributeAsBoolean ("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 {");
if (SymbolTable.Table.IsInterface (parms [i].CType)) {
var igen = SymbolTable.Table.GetInterfaceGen (parms [i].CType);
sw.WriteLine ("\t\t\t\treturn {0}.GetObject (Args [{1}] as GLib.Object);", igen.QualifiedAdapterName, i);
} else {
sw.WriteLine ("\t\t\t\treturn ({0}) Args [{1}];", parms [i].CSType, i);
}
sw.WriteLine ("\t\t\t}");
}
if (parms[i].PassAs != "") {
sw.WriteLine ("\t\t\tset {");
if (SymbolTable.Table.IsInterface (parms [i].CType)) {
var igen = SymbolTable.Table.GetInterfaceGen (parms [i].CType);
sw.WriteLine ("\t\t\t\tArgs [{0}] = value is {1} ? (value as {1}).Implementor : value;", i, igen.AdapterName);
} else {
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\t{0}.AddSignalHandler ({1}, value{2});", target, CName, args_type);
sw.WriteLine("\t\t\t}");
sw.WriteLine("\t\t\tremove {");
sw.WriteLine("\t\t\t\t{0}.RemoveSignalHandler ({1}, value);", target, CName);
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++;
}
}
}