mirror of
https://github.com/Ryujinx/GtkSharp.git
synced 2024-09-07 23:43:18 +02:00
342 lines
9.8 KiB
C#
342 lines
9.8 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.Collections.Generic;
|
|
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 IList<ClassField> class_fields = new List<ClassField> ();
|
|
// The default handlers of these signals need to be overridden with g_signal_override_class_closure
|
|
protected IList<GObjectVM> virtual_methods = new List<GObjectVM> ();
|
|
// virtual methods that are generated as an IntPtr in the class struct
|
|
protected IList<VirtualMethod> hidden_vms = new List<VirtualMethod> ();
|
|
protected IList<InterfaceVM> interface_vms = new List<InterfaceVM> ();
|
|
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.GetAttributeAsBoolean ("hidden")) {
|
|
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, GetMethod (target_name), this);
|
|
} else
|
|
vm = new GObjectVM (vm_elem, this);
|
|
|
|
if (vm_elem.GetAttributeAsBoolean ("padding") || vm_elem.GetAttributeAsBoolean ("hidden"))
|
|
hidden_vms.Add (vm);
|
|
else {
|
|
if (vm is GObjectVM) {
|
|
virtual_methods.Add ((GObjectVM)vm);
|
|
} else {
|
|
interface_vms.Add ((InterfaceVM)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 || class_struct_name == "GtkWidgetClass");
|
|
}
|
|
}
|
|
|
|
protected override bool CanGenerateABIStruct {
|
|
get {
|
|
if (!abi_fields_valid) {
|
|
Console.WriteLine("invalid fields");
|
|
return false;
|
|
}
|
|
|
|
// No instance structure for interfaces
|
|
if (is_interface)
|
|
return false;
|
|
|
|
return class_struct_name != null;
|
|
}
|
|
}
|
|
|
|
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 (GObjectVM 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;
|
|
}
|
|
}
|
|
}
|