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:
parent
6b6bb616b2
commit
f1011f687e
9 changed files with 405 additions and 2 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
|||
2002-09-13 Ricardo Fern<72>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
|
||||
|
|
|
@ -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 ");
|
||||
|
|
88
glade/HandlerNotFoundExeception.cs
Normal file
88
glade/HandlerNotFoundExeception.cs
Normal file
|
@ -0,0 +1,88 @@
|
|||
// HandlerNotFoundException.cs
|
||||
//
|
||||
// Author: Ricardo Fern<72>ndez Pascual <ric@users.sourceforge.net>
|
||||
//
|
||||
// (c) 2002 Ricardo Fern<72>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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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:
|
||||
|
|
149
glade/XML.custom
149
glade/XML.custom
|
@ -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
41
glib/SignalAttribute.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// SignalAttribute.cs
|
||||
//
|
||||
// Author:
|
||||
// Ricardo Fern<72>ndez Pascual <ric@users.sourceforge.net>
|
||||
//
|
||||
// (C) Ricardo Fern<72>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
50
sample/GladeTest.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
// GladeViewer.cs - Tests for LibGlade in C#
|
||||
//
|
||||
// Author: Ricardo Fern<72>ndez Pascual <ric@users.sourceforge.net>
|
||||
//
|
||||
// (c) 2002 Ricardo Fern<72>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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
58
sample/test.glade
Normal 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>
|
Loading…
Add table
Reference in a new issue