2002-09-13 Ricardo Fernndez Pascual <ric@users.sourceforge.net>

* glade/HandlerNotFoundExeception.cs: Added.
	* glade/Makefile.in
	* glade/XML.custom: Support for autoconnecting signals using
	reflection.
	* glib/SignalAttribute.cs: Added.
	* generator/Signal.cs: Mark events generated from glib signals
	with the "Signal" attribute.
	* sample/GladeTest.cs
	* sample/Makefile.in
	* sample/test.glade: Test of signal autoconnection.

svn path=/trunk/gtk-sharp/; revision=7430
This commit is contained in:
Ricardo Fernández Pascual 2002-09-13 11:38:36 +00:00
parent 6b6bb616b2
commit f1011f687e
9 changed files with 405 additions and 2 deletions

View File

@ -1,3 +1,16 @@
2002-09-13 Ricardo Fernández Pascual <ric@users.sourceforge.net>
* glade/HandlerNotFoundExeception.cs: Added.
* glade/Makefile.in
* glade/XML.custom: Support for autoconnecting signals using
reflection.
* glib/SignalAttribute.cs: Added.
* generator/Signal.cs: Mark events generated from glib signals
with the "Signal" attribute.
* sample/GladeTest.cs
* sample/Makefile.in
* sample/test.glade: Test of signal autoconnection.
2002-09-12 Rachel Hestilow <hestilow@ximian.com>
* sources/Gtk.metadata: Set null_ok on the callback argument

View File

@ -152,6 +152,7 @@ namespace GtkSharp.Generation {
string argsname;
string handler = GenHandler (out argsname);
sw.WriteLine("\t\t[GLib.Signal("+ cname + ")]");
sw.Write("\t\tpublic ");
if (elem.HasAttribute("new_flag") || (container_type != null && container_type.GetSignalRecursively (Name) != null) || (implementor != null && implementor.GetSignalRecursively (Name) != null))
sw.Write("new ");

View File

@ -0,0 +1,88 @@
// HandlerNotFoundException.cs
//
// Author: Ricardo Fernández Pascual <ric@users.sourceforge.net>
//
// (c) 2002 Ricardo Fernández Pascual
namespace Glade {
using System;
using System.Reflection;
using System.Runtime.Serialization;
/// <summary>
/// Exception thrown when signal autoconnection fails.
/// </summary>
[Serializable]
public class HandlerNotFoundException : Exception
{
string handler_name;
string signal_name;
EventInfo evnt;
Type delegate_type;
public HandlerNotFoundException (string handler_name, string signal_name,
EventInfo evnt, Type delegate_type)
{
this.handler_name = handler_name;
this.signal_name = signal_name;
this.evnt = evnt;
this.delegate_type = delegate_type;
}
protected HandlerNotFoundException (SerializationInfo info, StreamingContext context)
: base (info, context)
{
handler_name = info.GetString ("HandlerName");
signal_name = info.GetString ("SignalName");
evnt = info.GetValue ("Event", typeof (EventInfo)) as EventInfo;
delegate_type = info.GetValue ("DelegateType", typeof (Type)) as Type;
}
public override string Message
{
get {
return "No handler " + handler_name + " found for signal " + signal_name;
}
}
public string HandlerName
{
get {
return handler_name;
}
}
public string SignalName
{
get {
return signal_name;
}
}
public EventInfo Event
{
get {
return evnt;
}
}
public Type DelegateType
{
get {
return delegate_type;
}
}
public override void GetObjectData (SerializationInfo info, StreamingContext context)
{
base.GetObjectData (info, context);
info.AddValue ("HandlerName", handler_name);
info.AddValue ("SignalName", signal_name);
info.AddValue ("Event", evnt);
info.AddValue ("DelegateType", delegate_type);
}
}
}

View File

@ -9,7 +9,7 @@ windows:
linux: glade-sharp.dll
glade-sharp.dll: generated/*.cs
glade-sharp.dll: *.cs generated/*.cs
$(MCS) --unsafe --target library -r System.Drawing -L ../glib -L ../pango -L ../atk -L ../gdk -L ../gtk -r glib-sharp.dll -r pango-sharp.dll -r atk-sharp.dll -r gdk-sharp.dll -r gtk-sharp.dll -o glade-sharp.dll --recurse '*.cs'
clean:

View File

@ -45,4 +45,153 @@
return ret;
}
/* signal autoconnection using reflection */
/// <summary>Automatically connect signals</summary>
/// <remarks>Connects the signals defined in the glade file with handler methods
/// provided by the given object.</remarks>
public void Autoconnect (object handler)
{
SignalConnector sc = new SignalConnector (this, handler);
sc.Autoconnect ();
}
/// <summary>Automatically connect signals</summary>
/// <remarks>Connects the signals defined in the glade file with static handler
/// methods provided by the given type.</remarks>
public void Autoconnect (Type 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;
}
delegate void RawXMLConnectFunc (string handler_name, IntPtr objekt,
string signal_name, string signal_data,
IntPtr connect_object, int after, IntPtr user_data);
[DllImport("glade-2.0")]
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 (string handler_name, IntPtr objekt_ptr,
string signal_name, string signal_data,
IntPtr connect_object_ptr, int after, IntPtr user_data) {
GLib.Object objekt = GLib.Object.GetObject (objekt_ptr);
/* 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);
/* 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)
{
throw new HandlerNotFoundException (handler_name, signal_name, ei, delegate_type);
}
}
}
}
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), true);
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;
}
}
}

41
glib/SignalAttribute.cs Normal file
View File

@ -0,0 +1,41 @@
//
// SignalAttribute.cs
//
// Author:
// Ricardo Fernández Pascual <ric@users.sourceforge.net>
//
// (C) Ricardo Fernández Pascual <ric@users.sourceforge.net>
//
namespace GLib {
using System;
/// <summary>
/// Marks events genrated from glib signals
/// </summary>
///
/// <remarks>
/// This attribute indentifies events generated from glib signals
/// and allows obtaining its original name.
/// </remarks>
[Serializable]
public class SignalAttribute : Attribute
{
private string cname;
public SignalAttribute (string cname)
{
this.cname = cname;
}
private SignalAttribute () {}
public string CName
{
get {
return cname;
}
}
}
}

50
sample/GladeTest.cs Normal file
View File

@ -0,0 +1,50 @@
// GladeViewer.cs - Tests for LibGlade in C#
//
// Author: Ricardo Fernández Pascual <ric@users.sourceforge.net>
//
// (c) 2002 Ricardo Fernández Pascual
namespace GladeSamples {
using System;
using Gtk;
using Gnome;
using Glade;
using GtkSharp;
public class GladeTest : Program
{
public static void Main (string[] args)
{
new GladeTest (args).Run ();
}
public GladeTest (string[] args, params object[] props)
: base ("GladeTest", "0.1", Modules.UI, args, props)
{
Glade.XML gxml = new Glade.XML ("test.glade", "main_window", null);
gxml.Autoconnect (this);
}
public void OnWindowDeleteEvent (object o, DeleteEventArgs args)
{
Quit ();
args.RetVal = true;
}
public void OnButton1Clicked (Object b, EventArgs e)
{
Console.WriteLine ("Button 1 clicked");
}
public static void OnButton2Clicked (Object b, EventArgs e)
{
Console.WriteLine ("Button 2 clicked");
}
public void OnButton2Entered (Object b, EventArgs e)
{
Console.WriteLine ("Button 2 entered");
}
}
}

View File

@ -6,7 +6,7 @@ MCS=mcs
@ENABLE_GLADE_TRUE@ GLADE_PATH=-L ../glade
@ENABLE_GLADE_TRUE@ GLADE_ASSEMBLY=-r glade-sharp.dll
@ENABLE_GLADE_TRUE@ GLADE_TARGETS=glade-viewer.exe
@ENABLE_GLADE_TRUE@ GLADE_TARGETS=glade-viewer.exe glade-test.exe
local_paths=-L ../glib -L ../pango -L ../atk -L ../gdk -L ../gtk $(GNOME_PATH) $(GLADE_PATH)
all_assemblies=-r glib-sharp.dll -r pango-sharp.dll -r atk-sharp.dll -r gdk-sharp.dll -r gtk-sharp.dll $(GNOME_ASSEMBLY) $(GLADE_ASSEMBLY) -r System.Drawing
@ -50,6 +50,9 @@ treeviewdemo.exe: TreeViewDemo.cs
glade-viewer.exe: GladeViewer.cs
$(MCS) --unsafe -o glade-viewer.exe $(local_paths) $(all_assemblies) GladeViewer.cs
glade-test.exe: GladeTest.cs
$(MCS) --unsafe -o glade-test.exe $(local_paths) $(all_assemblies) GladeTest.cs
clean:
rm -f *.exe

58
sample/test.glade Normal file
View File

@ -0,0 +1,58 @@
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
<glade-interface>
<widget class="GtkWindow" id="main_window">
<property name="visible">True</property>
<property name="title" translatable="yes">Glade# test</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<signal name="delete_event" handler="OnWindowDeleteEvent" last_modification_time="Tue, 03 Sep 2002 14:47:57 GMT"/>
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkButton" id="button1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Click here</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<signal name="clicked" handler="OnButton1Clicked" last_modification_time="Tue, 13 Aug 2002 15:24:35 GMT"/>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="button2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Don't click here</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<signal name="clicked" handler="OnButton2Clicked" last_modification_time="Tue, 13 Aug 2002 15:24:35 GMT"/>
<signal name="enter" handler="OnButton2Entered" last_modification_time="Wed, 04 Sep 2002 14:04:40 GMT"/>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>