GtkSharp/glade/XML.custom
Christian Hoff 7b752d233c 2009-09-03 Christian Hoff <christian_hoff@gmx.net>
* glib/Global.cs: Kill the calling convention field again.
	It breaks GLib 2.x compatibility in the generator and there is
	probably no need to make the calling convention configurable.
	* .cs, *.custom: Hardcode Cdecl calling convention instead of
	using GLib's field.

svn path=/trunk/gtk-sharp/; revision=141283
2009-09-03 19:50:53 +00:00

436 lines
14 KiB
Text

// WARNING: This file is in UTF8 format due to the use of &atilde;
// XML.custom
//
// Author: Ricardo Fernández Pascual <ric@users.sourceforge.net>
//
// Copyright (c) 2002 Ricardo Fernández Pascual
//
// Field binding code by Rachel Hestilow <hestilow@ximian.com>
// Copyright (c) 2003 Rachel Hestilow
//
// This code is inserted after the automatically generated code.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the Lesser 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser 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.
// keep this around so it doesn't get GC'd
static GladeSharp.XMLCustomWidgetHandlerWrapper callback_wrapper = null;
[DllImport ("libglade-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void glade_set_custom_handler (GladeSharp.XMLCustomWidgetHandlerNative handler, IntPtr user_data);
public static Glade.XMLCustomWidgetHandler CustomHandler {
set {
callback_wrapper = new GladeSharp.XMLCustomWidgetHandlerWrapper (value);
glade_set_custom_handler(callback_wrapper.NativeDelegate, IntPtr.Zero);
}
}
[Obsolete ("Replaced by CustomHandler property.")]
static public void SetCustomHandler (Glade.XMLCustomWidgetHandler handler)
{
CustomHandler = handler;
}
[DllImport("gladesharpglue-3")]
static extern IntPtr gtksharp_glade_xml_get_filename (IntPtr raw);
public string Filename {
get {
string ret;
IntPtr ptr = gtksharp_glade_xml_get_filename (Handle);
if (ptr == IntPtr.Zero)
{
// from resource
ret = System.Reflection.Assembly.GetCallingAssembly ().Location;
}
else
{
ret = GLib.Marshaller.Utf8PtrToString (ptr);
}
return ret;
}
}
public Gtk.Widget this [string name] {
get {
return GetWidget (name);
}
}
[DllImport ("libglade-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr glade_get_widget_name (IntPtr widget);
static public string GetWidgetName (Gtk.Widget w) {
string ret;
IntPtr ptr = glade_get_widget_name (w.Handle);
if (ptr == IntPtr.Zero)
ret = "";
else
ret = GLib.Marshaller.Utf8PtrToString (ptr);
return ret;
}
[DllImport ("libglade-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr glade_get_widget_tree (IntPtr widget);
static public Glade.XML GetWidgetTree (Gtk.Widget w) {
IntPtr ret_raw = glade_get_widget_tree (w.Handle);
Glade.XML ret = GLib.Object.GetObject (ret_raw, false) as Glade.XML;
return ret;
}
/* a constructor that reads the XML from a Stream */
[DllImport ("libglade-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr glade_xml_new_from_buffer(byte[] buffer, int size, IntPtr root, IntPtr domain);
public XML (System.IO.Stream s, string root, string domain) : base (IntPtr.Zero)
{
if (GetType() != typeof (XML))
throw new InvalidOperationException ("Can't chain to this constructor from subclasses.");
if (s == null)
throw new ArgumentNullException ("s");
int size = (int) s.Length;
byte[] buffer = new byte[size];
s.Read (buffer, 0, size);
IntPtr nroot = GLib.Marshaller.StringToPtrGStrdup (root);
IntPtr ndomain = GLib.Marshaller.StringToPtrGStrdup (domain);
Raw = glade_xml_new_from_buffer(buffer, size, nroot, ndomain);
GLib.Marshaller.Free (nroot);
GLib.Marshaller.Free (ndomain);
}
public XML (string resource_name, string root) : this (System.Reflection.Assembly.GetEntryAssembly (), resource_name, root, null)
{
}
public XML (System.Reflection.Assembly assembly, string resource_name, string root, string domain) : base (IntPtr.Zero)
{
if (GetType() != typeof (XML))
throw new InvalidOperationException ("Cannot chain to this constructor from subclasses.");
if (assembly == null)
assembly = System.Reflection.Assembly.GetCallingAssembly ();
System.IO.Stream s = assembly.GetManifestResourceStream (resource_name);
if (s == null)
throw new ArgumentException ("Cannot get resource file '" + resource_name + "'",
"resource_name");
int size = (int) s.Length;
byte[] buffer = new byte[size];
s.Read (buffer, 0, size);
s.Close ();
IntPtr nroot = GLib.Marshaller.StringToPtrGStrdup (root);
IntPtr ndomain = GLib.Marshaller.StringToPtrGStrdup (domain);
Raw = glade_xml_new_from_buffer(buffer, size, nroot, ndomain);
GLib.Marshaller.Free (nroot);
GLib.Marshaller.Free (ndomain);
}
/* signal autoconnection using reflection */
public void Autoconnect (object handler)
{
BindFields (handler);
SignalConnector sc = new SignalConnector (this, handler);
sc.Autoconnect ();
}
public void Autoconnect (Type handler_class)
{
BindFields (handler_class);
SignalConnector sc = new SignalConnector (this, handler_class);
sc.Autoconnect ();
}
class SignalConnector
{
/* the Glade.XML object whose signals we want to connect */
XML gxml;
/* the object to look for handlers */
object handler_object;
/* the type to look for handlers if no object has been specified */
Type handler_type;
public SignalConnector (XML gxml, object handler)
{
this.gxml = gxml;
this.handler_object = handler;
this.handler_type = handler.GetType ();
}
public SignalConnector (XML gxml, Type type)
{
this.gxml = gxml;
this.handler_object = null;
this.handler_type = type;
}
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
delegate void RawXMLConnectFunc (IntPtr handler_name, IntPtr objekt,
IntPtr signal_name, IntPtr signal_data,
IntPtr connect_object, int after, IntPtr user_data);
[DllImport ("libglade-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void glade_xml_signal_autoconnect_full (IntPtr raw, RawXMLConnectFunc func,
IntPtr user_data);
public void Autoconnect () {
RawXMLConnectFunc cf = new RawXMLConnectFunc (ConnectFunc);
glade_xml_signal_autoconnect_full (gxml.Handle, cf, IntPtr.Zero);
}
void ConnectFunc (IntPtr native_handler_name, IntPtr objekt_ptr,
IntPtr native_signal_name, IntPtr native_signal_data,
IntPtr connect_object_ptr, int after, IntPtr user_data) {
GLib.Object objekt = GLib.Object.GetObject (objekt_ptr, false);
string handler_name = GLib.Marshaller.Utf8PtrToString (native_handler_name);
string signal_name = GLib.Marshaller.Utf8PtrToString (native_signal_name);
//string signal_data = GLib.Marshaller.Utf8PtrToString (native_signal_data);
/* if an connect_object_ptr is provided, use that as handler */
object connect_object =
connect_object_ptr == IntPtr.Zero
? handler_object
: GLib.Object.GetObject (connect_object_ptr, false);
/* search for the event to connect */
System.Reflection.MemberInfo[] evnts = objekt.GetType ().
FindMembers (System.Reflection.MemberTypes.Event,
System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.Static
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.NonPublic,
signalFilter, signal_name);
foreach (System.Reflection.EventInfo ei in evnts)
{
bool connected = false;
System.Reflection.MethodInfo add = ei.GetAddMethod ();
System.Reflection.ParameterInfo[] addpi = add.GetParameters ();
if (addpi.Length == 1)
{ /* this should be always true, unless there's something broken */
Type delegate_type = addpi[0].ParameterType;
/* look for an instance method */
if (connect_object != null) try
{
Delegate d = Delegate.CreateDelegate
(delegate_type, connect_object, handler_name);
add.Invoke (objekt, new object[] { d } );
connected = true;
}
catch (ArgumentException)
{
/* ignore if there is not such instance method */
}
/* look for a static method if no instance method has been found */
if (!connected && handler_type != null) try
{
Delegate d = Delegate.CreateDelegate
(delegate_type, handler_type, handler_name);
add.Invoke (objekt, new object[] { d } );
connected = true;
}
catch (ArgumentException)
{
/* ignore if there is not such static method */
}
if (!connected)
{
string msg = ExplainError (ei.Name, delegate_type, handler_type, handler_name);
throw new HandlerNotFoundException (msg, handler_name, signal_name, ei, delegate_type);
}
}
}
}
static string GetSignature (System.Reflection.MethodInfo method)
{
if (method == null)
return null;
System.Reflection.ParameterInfo [] parameters = method.GetParameters ();
System.Text.StringBuilder sb = new System.Text.StringBuilder ();
sb.Append ('(');
foreach (System.Reflection.ParameterInfo info in parameters) {
sb.Append (info.ParameterType.ToString ());
sb.Append (',');
}
if (sb.Length != 0)
sb.Length--;
sb.Append (')');
return sb.ToString ();
}
static string GetSignature (Type delegate_type)
{
System.Reflection.MethodInfo method = delegate_type.GetMethod ("Invoke");
return GetSignature (method);
}
const System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.Instance;
static string GetSignature (Type klass, string method_name)
{
try {
System.Reflection.MethodInfo method = klass.GetMethod (method_name, flags);
return GetSignature (method);
} catch {
// May be more than one method with that name and none matches
return null;
}
}
static string ExplainError (string event_name, Type deleg, Type klass, string method)
{
if (deleg == null || klass == null || method == null)
return null;
System.Text.StringBuilder sb = new System.Text.StringBuilder ();
string expected = GetSignature (deleg);
string actual = GetSignature (klass, method);
if (actual == null)
return null;
sb.AppendFormat ("The handler for the event {0} should take '{1}', " +
"but the signature of the provided handler ('{2}') is '{3}'\n",
event_name, expected, method, actual);
return sb.ToString ();
}
System.Reflection.MemberFilter signalFilter = new System.Reflection.MemberFilter (SignalFilter);
/* matches events to GLib signal names */
static bool SignalFilter (System.Reflection.MemberInfo m, object filterCriteria)
{
string signame = (filterCriteria as string);
object[] attrs = m.GetCustomAttributes (typeof (GLib.SignalAttribute), false);
if (attrs.Length > 0)
{
foreach (GLib.SignalAttribute a in attrs)
{
if (signame == a.CName)
{
return true;
}
}
return false;
}
else
{
/* this tries to match the names when no attibutes are present.
It is only a fallback. */
signame = signame.ToLower ().Replace ("_", "");
string evname = m.Name.ToLower ();
return signame == evname;
}
}
}
private void BindFields (object target, Type type)
{
System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.DeclaredOnly;
if (target != null)
flags |= System.Reflection.BindingFlags.Instance;
else
flags |= System.Reflection.BindingFlags.Static;
do {
System.Reflection.FieldInfo[] fields = type.GetFields (flags);
if (fields == null)
return;
foreach (System.Reflection.FieldInfo field in fields)
{
object[] attrs = field.GetCustomAttributes (typeof (WidgetAttribute), false);
if (attrs == null || attrs.Length == 0)
continue;
// The widget to field binding must be 1:1, so only check
// the first attribute.
WidgetAttribute attr = (WidgetAttribute) attrs[0];
Gtk.Widget widget;
if (attr.Specified)
widget = GetWidget (attr.Name);
else
widget = GetWidget (field.Name);
if (widget != null)
try {
field.SetValue (target, widget, flags, null, null);
} catch (Exception e) {
Console.WriteLine ("Unable to set value for field " + field.Name);
throw e;
}
}
type = type.BaseType;
}
while (type != typeof(object) && type != null);
}
public void BindFields (object target)
{
BindFields (target, target.GetType ());
}
public void BindFields (Type type)
{
BindFields (null, type);
}
public static Glade.XML FromStream (System.IO.Stream stream, string root, string domain)
{
return new Glade.XML (stream, root, domain);
}
public static Glade.XML FromAssembly (
System.Reflection.Assembly assembly, string resource_name, string root, string domain)
{
return new Glade.XML (assembly, resource_name, root, domain);
}
public static Glade.XML FromAssembly (string resource_name, string root, string domain)
{
return new Glade.XML (
System.Reflection.Assembly.GetCallingAssembly (), resource_name, root, domain);
}
[DllImport ("libglade-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr glade_xml_get_widget_prefix(IntPtr raw, IntPtr name);
public Gtk.Widget[] GetWidgetPrefix(string name)
{
IntPtr native = GLib.Marshaller.StringToPtrGStrdup (name);
IntPtr raw_ret = glade_xml_get_widget_prefix(Handle, native);
GLib.Marshaller.Free (native);
if (raw_ret == IntPtr.Zero)
return new Gtk.Widget [0];
GLib.List list = new GLib.List (raw_ret);
Gtk.Widget[] result = new Gtk.Widget [list.Count];
int i = 0;
foreach (Gtk.Widget w in list)
result [i++] = w;
return result;
}