2005-07-02 15:23:27 +00:00
|
|
|
// ObjectBase.cs - Base class for Object types
|
|
|
|
//
|
|
|
|
// Authors: Mike Kestner <mkestner@novell.com>
|
|
|
|
//
|
|
|
|
// Copyright (c) 2005 Novell, Inc.
|
2009-04-13 17:44:48 +00:00
|
|
|
// Copyright (c) 2009 Christian Hoff
|
2005-07-02 15:23:27 +00:00
|
|
|
//
|
|
|
|
// 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;
|
2009-04-13 17:44:48 +00:00
|
|
|
using System.Collections;
|
|
|
|
using System.IO;
|
2005-07-02 15:23:27 +00:00
|
|
|
using System.Xml;
|
|
|
|
|
|
|
|
public abstract class ObjectBase : HandleBase {
|
2009-04-13 17:44:48 +00:00
|
|
|
bool is_interface;
|
|
|
|
protected string class_struct_name = null;
|
2009-05-04 17:39:45 +00:00
|
|
|
bool class_fields_valid; // false if the class structure contains a bitfield or fields of unknown types
|
2009-04-13 17:44:48 +00:00
|
|
|
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();
|
2005-07-02 15:23:27 +00:00
|
|
|
|
2009-04-13 17:44:48 +00:00
|
|
|
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
|
2009-05-04 17:39:45 +00:00
|
|
|
ClassField field = new ClassField (member, this);
|
2009-04-13 17:44:48 +00:00
|
|
|
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);
|
2011-02-12 21:52:57 +00:00
|
|
|
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
|
2009-04-13 17:44:48 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2009-07-12 21:21:25 +00:00
|
|
|
|
2009-08-05 06:24:27 +00:00
|
|
|
public override string CallByName (string var)
|
2009-07-12 21:21:25 +00:00
|
|
|
{
|
2009-08-05 06:24:27 +00:00
|
|
|
return CallByName (var, false);
|
2009-07-12 21:21:25 +00:00
|
|
|
}
|
|
|
|
|
2009-08-05 06:24:27 +00:00
|
|
|
public abstract string CallByName (string var, bool owned);
|
|
|
|
|
Automatic memory management for opaque types [#49565]
* glib/Opaque.cs (Owned): new property saying whether or not gtk#
owns the memory.
(Opaque): Set Owned to true in the void ctor and false in the
IntPtr one.
(GetOpaque): add a new overload that can also create opaques, a la
GLib.Object.GetObject.
(Ref, Unref, Free): empty virtual methods to be overridden by
subclasses.
(set_Raw): Unref() and possibly Free() the old value, Ref() the
new one.
(~Opaque, Dispose): set Raw to IntPtr.Zero (triggering Free/Unref
if needed)
* parser/gapi2xml.pl (addReturnElem): if the method is named Copy
and returns a pointer, set the "owned" attribute on the
return-type.
* */*-api.raw: Regen
* generator/HandleBase.cs (FromNative): Add new
FromNative/FromNativeReturn overloads that takes a "bool owned"
param. Implement the 1-arg FromNative and FromNativeReturn in
terms of that.
* generator/ObjectBase.cs (FromNative): Implement HandleBase's new
overload. Use the two-arg version of GLib.Object.GetObject when
"owned" is true.
* generator/OpaqueGen.cs (Generate): Pull out Ref, Unref, and
Free/Destroy/Dispose methods and handle them specially by
overriding Opaque.Ref, .Unref, and .Free appropriately. (If any
of the methods are marked deprecated, output a deprecated
do-nothing method as well, to save us from having to write all
those deprecated methods by hand.)
(FromNative): use GetOpaque, passing "owned".
* generator/ReturnValue.cs (FromNative): if the value is a
HandleBase, pass Owned to its FromNative().
* generator/Parameters.cs (Owned): new property (for use on out
params)
(FromNative): Call FromNative() on the generatable, handling Owned
in the case of HandleBase.
* generator/ManagedCallString.cs:
* generator/MethodBody.cs:
* generator/Signal.cs: use param.FromNative() rather than
param.Generatable.FromNative(), to get ownership right.
* */*.metadata: Mark opaque ref/unref/free methods deprecated
(except where we were hiding them before). Add "owned" attributes
to return values and out params as needed.
* pango/AttrIterator.custom (GetFont): work around a
memory-management oddity of the underlying method.
* pango/AttrFontDesc.cs (AttrFontDesc): copy the passed-in
FontDescriptor, since the attribute will assume ownership of it.
* gtk/TreeView.custom (GetPathAtPos): set the "owned" flag on the
returned TreePaths.
* gtk/TargetList.custom: Remove refcounting stuff, which is
now handled automatically
* gtk/NodeStore.cs (GetPath): clear the Owned flag on the created
TreePath so that the underlying structure doesn't get freed when
the function returns
* gtkhtml/HTMLStream.custom (Destroy): hide this and then
reimplement it by hand to keep OpaqueGen from using it in
Dispose(), since calling it after an HTMLStream.Close() will
result in a crash.
svn path=/trunk/gtk-sharp/; revision=47928
2005-08-02 18:45:21 +00:00
|
|
|
public override string FromNative (string var, bool owned)
|
2005-07-02 15:23:27 +00:00
|
|
|
{
|
Automatic memory management for opaque types [#49565]
* glib/Opaque.cs (Owned): new property saying whether or not gtk#
owns the memory.
(Opaque): Set Owned to true in the void ctor and false in the
IntPtr one.
(GetOpaque): add a new overload that can also create opaques, a la
GLib.Object.GetObject.
(Ref, Unref, Free): empty virtual methods to be overridden by
subclasses.
(set_Raw): Unref() and possibly Free() the old value, Ref() the
new one.
(~Opaque, Dispose): set Raw to IntPtr.Zero (triggering Free/Unref
if needed)
* parser/gapi2xml.pl (addReturnElem): if the method is named Copy
and returns a pointer, set the "owned" attribute on the
return-type.
* */*-api.raw: Regen
* generator/HandleBase.cs (FromNative): Add new
FromNative/FromNativeReturn overloads that takes a "bool owned"
param. Implement the 1-arg FromNative and FromNativeReturn in
terms of that.
* generator/ObjectBase.cs (FromNative): Implement HandleBase's new
overload. Use the two-arg version of GLib.Object.GetObject when
"owned" is true.
* generator/OpaqueGen.cs (Generate): Pull out Ref, Unref, and
Free/Destroy/Dispose methods and handle them specially by
overriding Opaque.Ref, .Unref, and .Free appropriately. (If any
of the methods are marked deprecated, output a deprecated
do-nothing method as well, to save us from having to write all
those deprecated methods by hand.)
(FromNative): use GetOpaque, passing "owned".
* generator/ReturnValue.cs (FromNative): if the value is a
HandleBase, pass Owned to its FromNative().
* generator/Parameters.cs (Owned): new property (for use on out
params)
(FromNative): Call FromNative() on the generatable, handling Owned
in the case of HandleBase.
* generator/ManagedCallString.cs:
* generator/MethodBody.cs:
* generator/Signal.cs: use param.FromNative() rather than
param.Generatable.FromNative(), to get ownership right.
* */*.metadata: Mark opaque ref/unref/free methods deprecated
(except where we were hiding them before). Add "owned" attributes
to return values and out params as needed.
* pango/AttrIterator.custom (GetFont): work around a
memory-management oddity of the underlying method.
* pango/AttrFontDesc.cs (AttrFontDesc): copy the passed-in
FontDescriptor, since the attribute will assume ownership of it.
* gtk/TreeView.custom (GetPathAtPos): set the "owned" flag on the
returned TreePaths.
* gtk/TargetList.custom: Remove refcounting stuff, which is
now handled automatically
* gtk/NodeStore.cs (GetPath): clear the Owned flag on the created
TreePath so that the underlying structure doesn't get freed when
the function returns
* gtkhtml/HTMLStream.custom (Destroy): hide this and then
reimplement it by hand to keep OpaqueGen from using it in
Dispose(), since calling it after an HTMLStream.Close() will
result in a crash.
svn path=/trunk/gtk-sharp/; revision=47928
2005-08-02 18:45:21 +00:00
|
|
|
return "GLib.Object.GetObject(" + var + (owned ? ", true" : "") + ") as " + QualifiedName;
|
2005-07-02 15:23:27 +00:00
|
|
|
}
|
2009-04-13 17:44:48 +00:00
|
|
|
|
|
|
|
public string ClassStructName {
|
|
|
|
get {
|
|
|
|
return class_struct_name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-04 17:39:45 +00:00
|
|
|
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)
|
2009-04-13 17:44:48 +00:00
|
|
|
{
|
2009-05-04 17:39:45 +00:00
|
|
|
if (class_struct_name == null || !CanGenerateClassStruct) return;
|
|
|
|
|
|
|
|
StreamWriter sw = gen_info.Writer;
|
2009-04-13 17:44:48 +00:00
|
|
|
|
|
|
|
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;
|
2009-05-04 17:39:45 +00:00
|
|
|
field.Generate (gen_info, "\t\t\t");
|
2009-04-13 17:44:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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 ()
|
|
|
|
{
|
2011-02-20 18:11:08 +00:00
|
|
|
|
2009-04-13 17:44:48 +00:00
|
|
|
if (Parent != null && !(Parent as ObjectBase).ValidateForSubclass ())
|
|
|
|
return false;
|
|
|
|
|
2011-02-20 18:11:08 +00:00
|
|
|
LogWriter log = new LogWriter (QualifiedName);
|
|
|
|
|
2009-04-13 17:44:48 +00:00
|
|
|
ArrayList invalids = new ArrayList ();
|
|
|
|
|
|
|
|
foreach (GObjectVM vm in virtual_methods)
|
2011-02-20 18:11:08 +00:00
|
|
|
if (!vm.Validate (log))
|
2009-04-13 17:44:48 +00:00
|
|
|
invalids.Add (vm);
|
|
|
|
|
|
|
|
foreach (VirtualMethod invalid_vm in invalids) {
|
|
|
|
virtual_methods.Remove (invalid_vm);
|
|
|
|
hidden_vms.Add (invalid_vm);
|
|
|
|
}
|
|
|
|
invalids.Clear ();
|
2009-05-04 17:39:45 +00:00
|
|
|
|
|
|
|
class_fields_valid = true;
|
|
|
|
foreach (ClassField field in class_fields)
|
2011-02-20 18:11:08 +00:00
|
|
|
if (!field.Validate (log))
|
2009-05-04 17:39:45 +00:00
|
|
|
class_fields_valid = false;
|
2009-04-13 17:44:48 +00:00
|
|
|
|
|
|
|
foreach (InterfaceVM vm in interface_vms)
|
2011-02-20 18:11:08 +00:00
|
|
|
if (!vm.Validate (log))
|
2009-04-13 17:44:48 +00:00
|
|
|
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) {
|
2011-02-20 18:11:08 +00:00
|
|
|
if (!sig.Validate (log))
|
2009-04-13 17:44:48 +00:00
|
|
|
invalids.Add (sig);
|
|
|
|
}
|
|
|
|
foreach (Signal sig in invalids)
|
|
|
|
sigs.Remove (sig.Name);
|
|
|
|
|
|
|
|
return base.Validate ();
|
|
|
|
}
|
|
|
|
|
|
|
|
public virtual bool ValidateForSubclass ()
|
|
|
|
{
|
2011-02-20 18:11:08 +00:00
|
|
|
LogWriter log = new LogWriter (QualifiedName);
|
2009-04-13 17:44:48 +00:00
|
|
|
ArrayList invalids = new ArrayList ();
|
|
|
|
|
|
|
|
foreach (Signal sig in sigs.Values) {
|
2011-02-20 18:11:08 +00:00
|
|
|
if (!sig.Validate (log)) {
|
2009-04-13 17:44:48 +00:00
|
|
|
invalids.Add (sig);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
foreach (Signal sig in invalids)
|
|
|
|
sigs.Remove (sig.Name);
|
|
|
|
invalids.Clear ();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2005-07-02 15:23:27 +00:00
|
|
|
}
|
|
|
|
}
|