mirror of
https://github.com/Ryujinx/GtkSharp.git
synced 2025-01-11 22:15:48 +00:00
2ba496479f
* generator/*.cs: Add a LogWriter class which formats warnings consistently on the console. Supports the concept of non-fatal validation warnings, since it doesn't rely on the unrolling of the validation stack to associate a warning to a given type. Main purpose was to add a non-fatal warning for missing element_type attributes on list return values, though it results in cleaner log output, and also updates some warning messages to be more helpful in how to resolve them.
333 lines
12 KiB
C#
333 lines
12 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.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 || 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.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 {");
|
|
if (SymbolTable.Table.IsInterface (parms [i].CType))
|
|
sw.WriteLine ("\t\t\t\treturn {0}Adapter.GetObject (Args [{1}] as GLib.Object);", parms [i].CSType, 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))
|
|
sw.WriteLine ("\t\t\t\tArgs [{0}] = value is {1}Adapter ? (value as {1}Adapter).Implementor : value;", i, parms [i].CSType);
|
|
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\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++;
|
|
}
|
|
}
|
|
}
|
|
|