mirror of
https://github.com/Ryujinx/GtkSharp.git
synced 2024-09-09 00:13:20 +02:00
![Mike Kestner](/assets/img/avatar_default.png)
* 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.
325 lines
9.3 KiB
C#
325 lines
9.3 KiB
C#
// ObjectBase.cs - Base class for Object types
|
|
//
|
|
// Authors: Mike Kestner <mkestner@novell.com>
|
|
//
|
|
// 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) {
|
|
string target_name = vm_elem.HasAttribute ("target_method") ? vm_elem.GetAttribute ("target_method") : vm_elem.GetAttribute ("name");
|
|
vm = new InterfaceVM (vm_elem, methods [target_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 CallByName (string var)
|
|
{
|
|
return CallByName (var, false);
|
|
}
|
|
|
|
public abstract string CallByName (string var, bool owned);
|
|
|
|
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
|
|
* <signal> and <virtual_method> 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;
|
|
|
|
LogWriter log = new LogWriter (QualifiedName);
|
|
|
|
ArrayList invalids = new ArrayList ();
|
|
|
|
foreach (GObjectVM vm in virtual_methods)
|
|
if (!vm.Validate (log))
|
|
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 (log))
|
|
class_fields_valid = false;
|
|
|
|
foreach (InterfaceVM vm in interface_vms)
|
|
if (!vm.Validate (log))
|
|
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 (log))
|
|
invalids.Add (sig);
|
|
}
|
|
foreach (Signal sig in invalids)
|
|
sigs.Remove (sig.Name);
|
|
|
|
return base.Validate ();
|
|
}
|
|
|
|
public virtual bool ValidateForSubclass ()
|
|
{
|
|
LogWriter log = new LogWriter (QualifiedName);
|
|
ArrayList invalids = new ArrayList ();
|
|
|
|
foreach (Signal sig in sigs.Values) {
|
|
if (!sig.Validate (log)) {
|
|
invalids.Add (sig);
|
|
}
|
|
}
|
|
foreach (Signal sig in invalids)
|
|
sigs.Remove (sig.Name);
|
|
invalids.Clear ();
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|