[Gtk-sharp-list] Autoconnection of signals in Glade# (updated)
Ricardo Fernández Pascual
rfp1@ono.com
07 Sep 2002 21:33:26 +0200
--=-iS6WyCAUhuX5SGJ3Q/D+
Content-Type: text/plain; charset=ISO-8859-15
Content-Transfer-Encoding: quoted-printable
I have updated the patch. I think it is ready now. Let me know of any
problem.
(About the bug in the runtime: I can't create a testcase that crashes
mono. All I get is the expected NullReferenceException. It only crashes
with the sample program, and not always).
--=20
Ricardo Fern=E1ndez Pascual
ric@users.sourceforge.net
Murcia. Espa=F1a.
--=-iS6WyCAUhuX5SGJ3Q/D+
Content-Description: sample/GladeTest.cs
Content-Disposition: attachment; filename=GladeTest.cs
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-15
// GladeViewer.cs - Tests for LibGlade in C#
//
// Author: Ricardo Fern=E1ndez Pascual <ric@users.sourceforge.net>
//
// (c) 2002 Ricardo Fern=E1ndez Pascual
namespace GladeSamples {
using System;
=09
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)=20
: base ("GladeTest", "0.1", Modules.UI, args, props)
{
Glade.XML gxml =3D new Glade.XML ("test.glade", "main_window", null);
gxml.Autoconnect (this);
}
public void OnWindowDeleteEvent (object o, DeleteEventArgs args)=20
{
Quit ();
args.RetVal =3D true;
}
=09
public void OnButton1Clicked (Object b, EventArgs e)=20
{
Console.WriteLine ("Button 1 clicked");
}
public static void OnButton2Clicked (Object b, EventArgs e)=20
{
Console.WriteLine ("Button 2 clicked");
}
=09
public void OnButton2Entered (Object b, EventArgs e)=20
{
Console.WriteLine ("Button 2 entered");
}
}
}
--=-iS6WyCAUhuX5SGJ3Q/D+
Content-Description: sample/test.glade
Content-Type: application/x-glade
Content-Disposition: attachment; filename=test.glade
Content-Transfer-Encoding: base64
PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PiA8IS0tKi0gbW9kZTogeG1sIC0q
LS0+CjwhRE9DVFlQRSBnbGFkZS1pbnRlcmZhY2UgU1lTVEVNICJodHRwOi8vZ2xhZGUuZ25vbWUu
b3JnL2dsYWRlLTIuMC5kdGQiPgoKPGdsYWRlLWludGVyZmFjZT4KCjx3aWRnZXQgY2xhc3M9Ikd0
a1dpbmRvdyIgaWQ9Im1haW5fd2luZG93Ij4KICA8cHJvcGVydHkgbmFtZT0idmlzaWJsZSI+VHJ1
ZTwvcHJvcGVydHk+CiAgPHByb3BlcnR5IG5hbWU9InRpdGxlIiB0cmFuc2xhdGFibGU9InllcyI+
R2xhZGUjIHRlc3Q8L3Byb3BlcnR5PgogIDxwcm9wZXJ0eSBuYW1lPSJ0eXBlIj5HVEtfV0lORE9X
X1RPUExFVkVMPC9wcm9wZXJ0eT4KICA8cHJvcGVydHkgbmFtZT0id2luZG93X3Bvc2l0aW9uIj5H
VEtfV0lOX1BPU19OT05FPC9wcm9wZXJ0eT4KICA8cHJvcGVydHkgbmFtZT0ibW9kYWwiPkZhbHNl
PC9wcm9wZXJ0eT4KICA8cHJvcGVydHkgbmFtZT0icmVzaXphYmxlIj5UcnVlPC9wcm9wZXJ0eT4K
ICA8cHJvcGVydHkgbmFtZT0iZGVzdHJveV93aXRoX3BhcmVudCI+RmFsc2U8L3Byb3BlcnR5Pgog
IDxzaWduYWwgbmFtZT0iZGVsZXRlX2V2ZW50IiBoYW5kbGVyPSJPbldpbmRvd0RlbGV0ZUV2ZW50
IiBsYXN0X21vZGlmaWNhdGlvbl90aW1lPSJUdWUsIDAzIFNlcCAyMDAyIDE0OjQ3OjU3IEdNVCIv
PgoKICA8Y2hpbGQ+CiAgICA8d2lkZ2V0IGNsYXNzPSJHdGtWQm94IiBpZD0idmJveDEiPgogICAg
ICA8cHJvcGVydHkgbmFtZT0idmlzaWJsZSI+VHJ1ZTwvcHJvcGVydHk+CiAgICAgIDxwcm9wZXJ0
eSBuYW1lPSJob21vZ2VuZW91cyI+RmFsc2U8L3Byb3BlcnR5PgogICAgICA8cHJvcGVydHkgbmFt
ZT0ic3BhY2luZyI+MDwvcHJvcGVydHk+CgogICAgICA8Y2hpbGQ+Cgk8d2lkZ2V0IGNsYXNzPSJH
dGtCdXR0b24iIGlkPSJidXR0b24xIj4KCSAgPHByb3BlcnR5IG5hbWU9InZpc2libGUiPlRydWU8
L3Byb3BlcnR5PgoJICA8cHJvcGVydHkgbmFtZT0iY2FuX2ZvY3VzIj5UcnVlPC9wcm9wZXJ0eT4K
CSAgPHByb3BlcnR5IG5hbWU9ImxhYmVsIiB0cmFuc2xhdGFibGU9InllcyI+Q2xpY2sgaGVyZTwv
cHJvcGVydHk+CgkgIDxwcm9wZXJ0eSBuYW1lPSJ1c2VfdW5kZXJsaW5lIj5UcnVlPC9wcm9wZXJ0
eT4KCSAgPHByb3BlcnR5IG5hbWU9InJlbGllZiI+R1RLX1JFTElFRl9OT1JNQUw8L3Byb3BlcnR5
PgoJICA8c2lnbmFsIG5hbWU9ImNsaWNrZWQiIGhhbmRsZXI9Ik9uQnV0dG9uMUNsaWNrZWQiIGxh
c3RfbW9kaWZpY2F0aW9uX3RpbWU9IlR1ZSwgMTMgQXVnIDIwMDIgMTU6MjQ6MzUgR01UIi8+Cgk8
L3dpZGdldD4KCTxwYWNraW5nPgoJICA8cHJvcGVydHkgbmFtZT0icGFkZGluZyI+MDwvcHJvcGVy
dHk+CgkgIDxwcm9wZXJ0eSBuYW1lPSJleHBhbmQiPkZhbHNlPC9wcm9wZXJ0eT4KCSAgPHByb3Bl
cnR5IG5hbWU9ImZpbGwiPkZhbHNlPC9wcm9wZXJ0eT4KCTwvcGFja2luZz4KICAgICAgPC9jaGls
ZD4KCiAgICAgIDxjaGlsZD4KCTx3aWRnZXQgY2xhc3M9Ikd0a0J1dHRvbiIgaWQ9ImJ1dHRvbjIi
PgoJICA8cHJvcGVydHkgbmFtZT0idmlzaWJsZSI+VHJ1ZTwvcHJvcGVydHk+CgkgIDxwcm9wZXJ0
eSBuYW1lPSJjYW5fZm9jdXMiPlRydWU8L3Byb3BlcnR5PgoJICA8cHJvcGVydHkgbmFtZT0ibGFi
ZWwiIHRyYW5zbGF0YWJsZT0ieWVzIj5Eb24ndCBjbGljayBoZXJlPC9wcm9wZXJ0eT4KCSAgPHBy
b3BlcnR5IG5hbWU9InVzZV91bmRlcmxpbmUiPlRydWU8L3Byb3BlcnR5PgoJICA8cHJvcGVydHkg
bmFtZT0icmVsaWVmIj5HVEtfUkVMSUVGX05PUk1BTDwvcHJvcGVydHk+CgkgIDxzaWduYWwgbmFt
ZT0iY2xpY2tlZCIgaGFuZGxlcj0iT25CdXR0b24yQ2xpY2tlZCIgbGFzdF9tb2RpZmljYXRpb25f
dGltZT0iVHVlLCAxMyBBdWcgMjAwMiAxNToyNDozNSBHTVQiLz4KCSAgPHNpZ25hbCBuYW1lPSJl
bnRlciIgaGFuZGxlcj0iT25CdXR0b24yRW50ZXJlZCIgbGFzdF9tb2RpZmljYXRpb25fdGltZT0i
V2VkLCAwNCBTZXAgMjAwMiAxNDowNDo0MCBHTVQiLz4KCTwvd2lkZ2V0PgoJPHBhY2tpbmc+Cgkg
IDxwcm9wZXJ0eSBuYW1lPSJwYWRkaW5nIj4wPC9wcm9wZXJ0eT4KCSAgPHByb3BlcnR5IG5hbWU9
ImV4cGFuZCI+RmFsc2U8L3Byb3BlcnR5PgoJICA8cHJvcGVydHkgbmFtZT0iZmlsbCI+RmFsc2U8
L3Byb3BlcnR5PgoJPC9wYWNraW5nPgogICAgICA8L2NoaWxkPgogICAgPC93aWRnZXQ+CiAgPC9j
aGlsZD4KPC93aWRnZXQ+Cgo8L2dsYWRlLWludGVyZmFjZT4K
--=-iS6WyCAUhuX5SGJ3Q/D+
Content-Description:
Content-Disposition: inline; filename=ac.diff
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-15
Index: generator/Signal.cs
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /mono/gtk-sharp/generator/Signal.cs,v
retrieving revision 1.7
diff -u -r1.7 Signal.cs
--- generator/Signal.cs 20 Aug 2002 19:56:14 -0000 1.7
+++ generator/Signal.cs 7 Sep 2002 19:23:57 -0000
@@ -152,6 +152,7 @@
string argsname;=0D
string handler =3D GenHandler (out argsname);=0D
=20=0D
+ sw.WriteLine("\t\t[GLib.Signal("+ cname + ")]");=0D
sw.Write("\t\tpublic ");=0D
if (elem.HasAttribute("new_flag") || (container_type !=3D null && conta=
iner_type.GetSignalRecursively (Name) !=3D null) || (implementor !=3D null =
&& implementor.GetSignalRecursively (Name) !=3D null))=0D
sw.Write("new ");=0D
Index: glade/Makefile.in
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /mono/gtk-sharp/glade/Makefile.in,v
retrieving revision 1.2
diff -u -r1.2 Makefile.in
--- glade/Makefile.in 23 Aug 2002 21:22:15 -0000 1.2
+++ glade/Makefile.in 7 Sep 2002 19:23:57 -0000
@@ -9,7 +9,7 @@
=20
linux: glade-sharp.dll
=20
-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'
=20
clean:
Index: glade/XML.custom
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /mono/gtk-sharp/glade/XML.custom,v
retrieving revision 1.1
diff -u -r1.1 XML.custom
--- glade/XML.custom 12 Aug 2002 19:14:43 -0000 1.1
+++ glade/XML.custom 7 Sep 2002 19:23:58 -0000
@@ -45,4 +45,153 @@
return ret;
}
=20
+ /* 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 =3D new SignalConnector (this, handler);
+ sc.Autoconnect ();
+ }
=09
+ /// <summary>Automatically connect signals</summary>
+ /// <remarks>Connects the signals defined in the glade file with static =
handler=20
+ /// methods provided by the given type.</remarks>
+ public void Autoconnect (Type handler_class)
+ {
+ SignalConnector sc =3D new SignalConnector (this, handler_class);
+ sc.Autoconnect ();
+ }
+
+ class SignalConnector=20
+ {
+ /* the Glade.XML object whose signals we want to connect */
+ XML gxml;
+=09
+ /* the object to look for handlers */
+ object handler_object;
+=09
+ /* the type to look for handlers if no object has been specified */
+ Type handler_type;
+=09
+ public SignalConnector (XML gxml, object handler)=20
+ {
+ this.gxml =3D gxml;
+ this.handler_object =3D handler;
+ this.handler_type =3D handler.GetType ();
+ }
+=09
+ public SignalConnector (XML gxml, Type type)
+ {
+ this.gxml =3D gxml;
+ this.handler_object =3D null;
+ this.handler_type =3D type;
+ }
+ =09
+ delegate void RawXMLConnectFunc (string handler_name, IntPtr objekt,=20
+ string signal_name, string signal_data,=20
+ IntPtr connect_object, int after, IntPtr user_data);
+ =09
+ [DllImport("glade-2.0")]
+ static extern void glade_xml_signal_autoconnect_full (IntPtr raw, RawXM=
LConnectFunc func,
+ IntPtr user_data);
+ =09
+ public void Autoconnect () {
+ RawXMLConnectFunc cf =3D new RawXMLConnectFunc (ConnectFunc);
+ glade_xml_signal_autoconnect_full (gxml.Handle, cf, IntPtr.Zero);
+ }
+ =09
+ void ConnectFunc (string handler_name, IntPtr objekt_ptr,=20
+ string signal_name, string signal_data,=20
+ IntPtr connect_object_ptr, int after, IntPtr user_data) {
+ =09
+ GLib.Object objekt =3D GLib.Object.GetObject (objekt_ptr);
+=09
+ /* if an connect_object_ptr is provided, use that as handler */
+ object connect_object =3D=20
+ connect_object_ptr =3D=3D IntPtr.Zero=20
+ ? handler_object
+ : GLib.Object.GetObject (connect_object_ptr);
+ =09
+ /* search for the event to connect */
+ System.Reflection.MemberInfo[] evnts =3D objekt.GetType ().
+ FindMembers (System.Reflection.MemberTypes.Event,=20
+ System.Reflection.BindingFlags.Instance=20
+ | System.Reflection.BindingFlags.Static
+ | System.Reflection.BindingFlags.Public=20
+ | System.Reflection.BindingFlags.NonPublic,=20
+ signalFilter, signal_name);
+ foreach (System.Reflection.EventInfo ei in evnts)=20
+ {
+ bool connected =3D false;
+ System.Reflection.MethodInfo add =3D ei.GetAddMethod ();
+ System.Reflection.ParameterInfo[] addpi =3D add.GetParameters ();
+ if (addpi.Length =3D=3D 1)=20
+ { /* this should be always true, unless there's something broken */
+ Type delegate_type =3D addpi[0].ParameterType;
+=09
+ /* look for an instance method */
+ if (connect_object !=3D null) try=20
+ {
+ Delegate d =3D Delegate.CreateDelegate=20
+ (delegate_type, connect_object, handler_name);
+ add.Invoke (objekt, new object[] { d } );
+ connected =3D true;
+ }=20
+ catch (ArgumentException)=20
+ {
+ /* ignore if there is not such instance method */
+ }
+ =09
+ /* look for a static method if no instance method has been found */
+ if (!connected && handler_type !=3D null) try=20
+ {
+ Delegate d =3D Delegate.CreateDelegate=20
+ (delegate_type, handler_type, handler_name);
+ add.Invoke (objekt, new object[] { d } );
+ connected =3D true;
+ }=20
+ catch (ArgumentException)=20
+ {
+ /* ignore if there is not such static method */
+ }
+=09
+ if (!connected)=20
+ {
+ throw new HandlerNotFoundException (handler_name, signal_name, ei, =
delegate_type);
+ }
+ }
+ }
+=09
+ }
+=09
+ System.Reflection.MemberFilter signalFilter =3D new System.Reflection.M=
emberFilter (SignalFilter);
+ =09
+ /* matches events to GLib signal names */
+ static bool SignalFilter (System.Reflection.MemberInfo m, object filter=
Criteria)=20
+ {
+ string signame =3D (filterCriteria as string);
+ object[] attrs =3D m.GetCustomAttributes (typeof (GLib.SignalAttribute=
), true);
+ if (attrs.Length > 0)
+ {
+ foreach (GLib.SignalAttribute a in attrs)
+ {
+ if (signame =3D=3D a.CName)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ else
+ {
+ /* this tries to match the names when no attibutes are present.
+ It is only a fallback. */
+ signame =3D signame.ToLower ().Replace ("_", "");
+ string evname =3D m.Name.ToLower ();
+ return signame =3D=3D evname;
+ }
+ }
+ }
Index: sample/Makefile.in
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /mono/gtk-sharp/sample/Makefile.in,v
retrieving revision 1.16
diff -u -r1.16 Makefile.in
--- sample/Makefile.in 16 Aug 2002 05:00:31 -0000 1.16
+++ sample/Makefile.in 7 Sep 2002 19:23:59 -0000
@@ -6,7 +6,7 @@
=20
@ENABLE_GLADE_TRUE@ GLADE_PATH=3D-L ../glade
@ENABLE_GLADE_TRUE@ GLADE_ASSEMBLY=3D-r glade-sharp.dll
-@ENABLE_GLADE_TRUE@ GLADE_TARGETS=3Dglade-viewer.exe
+@ENABLE_GLADE_TRUE@ GLADE_TARGETS=3Dglade-viewer.exe glade-test.exe
=20
local_paths=3D-L ../glib -L ../pango -L ../atk -L ../gdk -L ../gtk $(GNOME=
_PATH) $(GLADE_PATH)=20
all_assemblies=3D-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 Syste=
m.Drawing
@@ -49,6 +49,9 @@
=20
glade-viewer.exe: GladeViewer.cs
$(MCS) --unsafe -o glade-viewer.exe $(local_paths) $(all_assemblies) Glad=
eViewer.cs
+
+glade-test.exe: GladeTest.cs
+ $(MCS) --unsafe -o glade-test.exe $(local_paths) $(all_assemblies) GladeT=
est.cs
=20
clean:
rm -f *.exe
--=-iS6WyCAUhuX5SGJ3Q/D+
Content-Description: glib/SignalAttribute.cs
Content-Disposition: inline; filename=SignalAttribute.cs
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-15
//
// SignalAttribute.cs
//
// Author:
// Ricardo Fern=E1ndez Pascual <ric@users.sourceforge.net>
//
// (C) Ricardo Fern=E1ndez 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=20
/// and allows obtaining its original name.
/// </remarks>
[Serializable]
public class SignalAttribute : Attribute=20
{
private string cname;
public SignalAttribute (string cname)
{
this.cname =3D cname;
}
private SignalAttribute () {}
public string CName=20
{
get {
return cname;
}
}
}
}
--=-iS6WyCAUhuX5SGJ3Q/D+
Content-Description: glade/HandlerNotFoundExeception.cs
Content-Disposition: inline; filename=HandlerNotFoundExeception.cs
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-15
// HandlerNotFoundException.cs=20
//
// Author: Ricardo Fern=E1ndez Pascual <ric@users.sourceforge.net>
//
// (c) 2002 Ricardo Fern=E1ndez 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=20
{
string handler_name;
string signal_name;
EventInfo evnt;
Type delegate_type;
public HandlerNotFoundException (string handler_name, string signal_name,=
=20
EventInfo evnt, Type delegate_type)
{
this.handler_name =3D handler_name;
this.signal_name =3D signal_name;
this.evnt =3D evnt;
this.delegate_type =3D delegate_type;
} =20
protected HandlerNotFoundException (SerializationInfo info, StreamingCont=
ext context)
: base (info, context)
{
handler_name =3D info.GetString ("HandlerName");
signal_name =3D info.GetString ("SignalName");
evnt =3D info.GetValue ("Event", typeof (EventInfo)) as EventInfo;
delegate_type =3D info.GetValue ("DelegateType", typeof (Type)) as Type;
}
public override string Message
{
get {=20
return "No handler " + handler_name + " found for signal " + signal_nam=
e;
}
}
public string HandlerName
{
get {=20
return handler_name;
}
}
public string SignalName
{
get {
return signal_name;
}
}
public EventInfo Event
{
get {
return evnt;
}
}
public Type DelegateType=20
{
get {
return delegate_type;
}
}
public override void GetObjectData (SerializationInfo info, StreamingCont=
ext context)
{
base.GetObjectData (info, context);
info.AddValue ("HandlerName", handler_name);
info.AddValue ("SignalName", signal_name);
info.AddValue ("Event", evnt);
info.AddValue ("DelegateType", delegate_type);
}
}
}
--=-iS6WyCAUhuX5SGJ3Q/D+--