diff --git a/ChangeLog b/ChangeLog
index 2cde164ef..92fdbec57 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2004-12-23  Mike Kestner  <mkestner@novell.com>
+
+	* glib/ClassInitializerAttribute.cs : new attr for identifying type.
+	inialization methods to be run by RegisterGType.
+	* glib/Makefile.am : add file.
+	* glib/Object.cs : add private method to invoke ClassInitializers.
+	* gtk/glue/widget.c : some new glue for binding registration.
+	* gtk/BindingAttribute.cs : new attr for registering key bindings.
+	* gtk/Makefile.am : add file.
+	* gtk/Widget.custom : add ClassInitializer method to scan types
+	for [Binding] and register key bindings.
+
 2004-12-22  Dan Winship  <danw@novell.com>
 
 	* generator/Signal.cs: fix some WriteLine()s that should have been
diff --git a/doc/ChangeLog b/doc/ChangeLog
index 22ec85296..39e6f472a 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,8 @@
+2004-12-23  Mike Kestner  <mkestner@novell.com>
+
+	* en/GLib/ClassInitializerAttribute.xml : doc new attr.
+	* en/Gtk/BindingAttribute.xml : doc new attr.
+
 2004-12-22  Dan Winship  <danw@novell.com>
 
 	* en/Gtk/Decorated.xml:
diff --git a/doc/en/GLib/ClassInitializerAttribute.xml b/doc/en/GLib/ClassInitializerAttribute.xml
new file mode 100644
index 000000000..9dc406ceb
--- /dev/null
+++ b/doc/en/GLib/ClassInitializerAttribute.xml
@@ -0,0 +1,33 @@
+<Type Name="ClassInitializerAttribute" FullName="GLib.ClassInitializerAttribute">
+  <TypeSignature Language="C#" Value="public sealed class ClassInitializerAttribute : System.Attribute" Maintainer="auto" />
+  <AssemblyInfo>
+    <AssemblyName>glib-sharp</AssemblyName>
+    <AssemblyPublicKey>[00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00 00 24 00 00 52 53 41 31 00 04 00 00 01 00 01 00 71 EB 6C 55 75 52 9C BF 72 44 F7 A6 EA 05 62 84 F9 EA E0 3B CF F2 CC 13 2C 9C 49 0A B3 09 EA B0 B5 6B CE 44 9D F5 03 D9 C0 A8 1E 52 05 85 CD BE 70 E2 FB 90 43 4B AC 04 FA 62 22 A8 00 98 B7 A1 A7 B3 AF 99 1A 41 23 24 BB 43 25 F6 B8 65 BB 64 EB F6 D1 C2 06 D5 73 2D DF BC 70 A7 38 9E E5 3E 0C 24 6E 32 79 74 1A D0 05 03 E4 98 42 E1 9B F3 7B 19 8B 40 21 26 CB 36 89 C2 EA 64 96 A4 7C B4]</AssemblyPublicKey>
+    <AssemblyVersion>2.0.0.0</AssemblyVersion>
+    <AssemblyCulture>neutral</AssemblyCulture>
+    <Attributes />
+  </AssemblyInfo>
+  <ThreadSafetyStatement>Gtk# is thread aware, but not thread safe; See the <link location="node:gtk-sharp/programming/threads">Gtk# Thread Programming</link> for details.</ThreadSafetyStatement>
+  <Docs>
+    <summary>Identifies a class initialization method to call when GTypes are registered.</summary>
+    <remarks />
+  </Docs>
+  <Base>
+    <BaseTypeName>System.Attribute</BaseTypeName>
+  </Base>
+  <Interfaces />
+  <Attributes />
+  <Members>
+    <Member MemberName=".ctor">
+      <MemberSignature Language="C#" Value="public ClassInitializerAttribute ();" />
+      <MemberType>Constructor</MemberType>
+      <ReturnValue />
+      <Parameters />
+      <Docs>
+        <summary>Constructs an attribute.</summary>
+        <returns>a <see cref="T:GLib.ClassInitializerAttribute" /></returns>
+        <remarks />
+      </Docs>
+    </Member>
+  </Members>
+</Type>
diff --git a/doc/en/Gtk/BindingAttribute.xml b/doc/en/Gtk/BindingAttribute.xml
new file mode 100644
index 000000000..3df536889
--- /dev/null
+++ b/doc/en/Gtk/BindingAttribute.xml
@@ -0,0 +1,116 @@
+<Type Name="BindingAttribute" FullName="Gtk.BindingAttribute">
+  <TypeSignature Language="C#" Value="public sealed class BindingAttribute : System.Attribute" Maintainer="auto" />
+  <AssemblyInfo>
+    <AssemblyName>gtk-sharp</AssemblyName>
+    <AssemblyPublicKey>[00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00 00 24 00 00 52 53 41 31 00 04 00 00 01 00 01 00 71 EB 6C 55 75 52 9C BF 72 44 F7 A6 EA 05 62 84 F9 EA E0 3B CF F2 CC 13 2C 9C 49 0A B3 09 EA B0 B5 6B CE 44 9D F5 03 D9 C0 A8 1E 52 05 85 CD BE 70 E2 FB 90 43 4B AC 04 FA 62 22 A8 00 98 B7 A1 A7 B3 AF 99 1A 41 23 24 BB 43 25 F6 B8 65 BB 64 EB F6 D1 C2 06 D5 73 2D DF BC 70 A7 38 9E E5 3E 0C 24 6E 32 79 74 1A D0 05 03 E4 98 42 E1 9B F3 7B 19 8B 40 21 26 CB 36 89 C2 EA 64 96 A4 7C B4]</AssemblyPublicKey>
+    <AssemblyVersion>2.0.0.0</AssemblyVersion>
+    <AssemblyCulture>neutral</AssemblyCulture>
+    <Attributes />
+  </AssemblyInfo>
+  <ThreadSafetyStatement>Gtk# is thread aware, but not thread safe; See the <link location="node:gtk-sharp/programming/threads">Gtk# Thread Programming</link> for details.</ThreadSafetyStatement>
+  <Docs>
+    <summary>Registers a key binding for a class.</summary>
+    <remarks />
+  </Docs>
+  <Base>
+    <BaseTypeName>System.Attribute</BaseTypeName>
+  </Base>
+  <Interfaces />
+  <Attributes>
+    <Attribute>
+      <AttributeName>System.AttributeUsageAttribute</AttributeName>
+    </Attribute>
+  </Attributes>
+  <Members>
+    <Member MemberName=".ctor">
+      <MemberSignature Language="C#" Value="public BindingAttribute (Gdk.Key key, string handler, object [] parms);" />
+      <MemberType>Constructor</MemberType>
+      <ReturnValue />
+      <Parameters>
+        <Parameter Name="key" Type="Gdk.Key" />
+        <Parameter Name="handler" Type="System.String" />
+        <Parameter Name="parms" Type="System.Object[]" />
+      </Parameters>
+      <Docs>
+        <summary>Constructs a Binding attribute with no key modifier.</summary>
+        <param name="key">a key value</param>
+        <param name="handler">name of the instance method to call.</param>
+        <param name="parms">an array containing the parameters to pass to the handler.</param>
+        <returns>a <see cref="T:Gtk.BindingAttribute" /></returns>
+        <remarks />
+      </Docs>
+    </Member>
+    <Member MemberName=".ctor">
+      <MemberSignature Language="C#" Value="public BindingAttribute (Gdk.Key key, Gdk.ModifierType mod, string handler, object [] parms);" />
+      <MemberType>Constructor</MemberType>
+      <ReturnValue />
+      <Parameters>
+        <Parameter Name="key" Type="Gdk.Key" />
+        <Parameter Name="mod" Type="Gdk.ModifierType" />
+        <Parameter Name="handler" Type="System.String" />
+        <Parameter Name="parms" Type="System.Object[]" />
+      </Parameters>
+      <Docs>
+        <summary>Constructs a Binding attribute for a key and modifier.</summary>
+        <param name="key">a key value</param>
+        <param name="mod">a modifier type, like ctrl or shift</param>
+        <param name="handler">name of the instance method to call.</param>
+        <param name="parms">an array containing the parameters to pass to the handler.</param>
+        <returns>a <see cref="T:Gtk.BindingAttribute" /></returns>
+        <remarks />
+      </Docs>
+    </Member>
+    <Member MemberName="Key">
+      <MemberSignature Language="C#" Value="public Gdk.Key Key { get; };" />
+      <MemberType>Property</MemberType>
+      <ReturnValue>
+        <ReturnType>Gdk.Key</ReturnType>
+      </ReturnValue>
+      <Parameters />
+      <Docs>
+        <summary>The key value</summary>
+        <returns>a <see cref="T:Gdk.Key" /></returns>
+        <remarks />
+      </Docs>
+    </Member>
+    <Member MemberName="Mod">
+      <MemberSignature Language="C#" Value="public Gdk.ModifierType Mod { get; };" />
+      <MemberType>Property</MemberType>
+      <ReturnValue>
+        <ReturnType>Gdk.ModifierType</ReturnType>
+      </ReturnValue>
+      <Parameters />
+      <Docs>
+        <summary>The key modifier, such as ctrl or shift.</summary>
+        <returns>a <see cref="T:Gdk.ModifierType" /></returns>
+        <remarks />
+      </Docs>
+    </Member>
+    <Member MemberName="Handler">
+      <MemberSignature Language="C#" Value="public string Handler { get; };" />
+      <MemberType>Property</MemberType>
+      <ReturnValue>
+        <ReturnType>System.String</ReturnType>
+      </ReturnValue>
+      <Parameters />
+      <Docs>
+        <summary>The name of the instance method to call on activation.</summary>
+        <returns>a <see cref="T:System.String" /></returns>
+        <remarks />
+      </Docs>
+    </Member>
+    <Member MemberName="Parms">
+      <MemberSignature Language="C#" Value="public object [] Parms { get; };" />
+      <MemberType>Property</MemberType>
+      <ReturnValue>
+        <ReturnType>System.Object[]</ReturnType>
+      </ReturnValue>
+      <Parameters />
+      <Docs>
+        <summary>An Array of parameters to pass to the Handler.</summary>
+        <returns>a <see cref="T:System.Object[]" /></returns>
+        <remarks />
+      </Docs>
+    </Member>
+  </Members>
+</Type>
diff --git a/glib/ClassInitializerAttribute.cs b/glib/ClassInitializerAttribute.cs
new file mode 100644
index 000000000..15d3dd699
--- /dev/null
+++ b/glib/ClassInitializerAttribute.cs
@@ -0,0 +1,30 @@
+// ClassInitializerAttribute.cs
+//
+// Author:   Mike Kestner  <mkestner@novell.com>
+//
+// Copyright (c) 2004 Novell, Inc.
+//
+// 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.
+
+
+namespace GLib {
+
+	using System;
+
+	public sealed class ClassInitializerAttribute : Attribute 
+	{
+		public ClassInitializerAttribute () {}
+	}
+}
diff --git a/glib/Makefile.am b/glib/Makefile.am
index ff59316c8..941d2c2ee 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -12,6 +12,7 @@ references =
 sources =		 			\
 	Argv.cs					\
 	Boxed.cs				\
+	ClassInitializerAttribute.cs		\
 	ConnectBeforeAttribute.cs		\
 	DefaultSignalHandlerAttribute.cs	\
 	DelegateWrapper.cs			\
diff --git a/glib/Object.cs b/glib/Object.cs
index 837e7178e..0352799e7 100644
--- a/glib/Object.cs
+++ b/glib/Object.cs
@@ -122,10 +122,7 @@ namespace GLib {
 				if (baseinfo == minfo)
 					continue;
 
-				foreach (object attr in baseinfo.GetCustomAttributes (true)) {
-					if (attr.ToString () != "GLib.DefaultSignalHandlerAttribute")
-						continue;
-
+				foreach (object attr in baseinfo.GetCustomAttributes (typeof (DefaultSignalHandlerAttribute), true)) {
 					DefaultSignalHandlerAttribute sigattr = attr as DefaultSignalHandlerAttribute;
 					MethodInfo connector = sigattr.Type.GetMethod (sigattr.ConnectionMethod, BindingFlags.Static | BindingFlags.NonPublic);
 					object[] parms = new object [1];
@@ -137,6 +134,15 @@ namespace GLib {
 					
 		}
 
+		private static void InvokeClassInitializers (GType gtype, System.Type t)
+		{
+			object[] parms = {gtype, t};
+			BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
+			foreach (MethodInfo minfo in t.GetMethods(flags))
+				foreach (object attr in minfo.GetCustomAttributes (typeof (ClassInitializerAttribute), true))
+					minfo.Invoke (null, parms);
+		}
+
 		[DllImport("glibsharpglue-2")]
 		static extern IntPtr gtksharp_register_type (string name, IntPtr parent_type);
 
@@ -147,6 +153,7 @@ namespace GLib {
 			GLib.ObjectManager.RegisterType (name, t.FullName, t.Assembly.GetName().Name);
 			GType gtype = new GType (gtksharp_register_type (name, parent_gtype.Val));
 			ConnectDefaultHandlers (gtype, t);
+			InvokeClassInitializers (gtype, t);
 			g_types[t] = gtype;
 			return gtype;
 		}
diff --git a/gtk/BindingAttribute.cs b/gtk/BindingAttribute.cs
new file mode 100644
index 000000000..56ee61ff6
--- /dev/null
+++ b/gtk/BindingAttribute.cs
@@ -0,0 +1,68 @@
+// BindingAttribute.cs - Attribute to specify key bindings
+//
+// Author: Mike Kestner  <mkestner@ximian.com>
+//
+// Copyright (c) 2004 Novell, Inc.
+//
+// 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.
+
+
+namespace Gtk {
+
+	using System;
+
+	[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+	public sealed class BindingAttribute : Attribute {
+		Gdk.Key key;
+		Gdk.ModifierType mod;
+		string handler;
+		object[] parms;
+
+		public BindingAttribute (Gdk.Key key, string handler, params object[] parms) : this (key, 0, handler, parms) {}
+
+		public BindingAttribute (Gdk.Key key, Gdk.ModifierType mod, string handler, params object[] parms)
+		{
+			this.key = key;
+			this.mod = mod;
+			this.handler = handler;
+			this.parms = parms;
+		}
+
+		public Gdk.Key Key {
+			get {
+				return key;
+			}
+		}
+
+		public Gdk.ModifierType Mod {
+			get {
+				return mod;
+			}
+		}
+
+		public string Handler {
+			get {
+				return handler;
+			}
+		}
+
+		public object[] Parms {
+			get {
+				return parms;
+			}
+		}
+	}
+}
+
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 7fc1f59e7..96387cfa5 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -19,6 +19,7 @@ DISTCLEANFILES = $(ASSEMBLY).config AssemblyInfo.cs
 sources = 				\
 	ActionEntry.cs			\
 	Application.cs			\
+	BindingAttribute.cs		\
 	ChildPropertyAttribute.cs	\
 	ITreeNode.cs			\
 	NodeCellDataFunc.cs		\
diff --git a/gtk/Widget.custom b/gtk/Widget.custom
index b5010b188..7de486808 100644
--- a/gtk/Widget.custom
+++ b/gtk/Widget.custom
@@ -231,3 +231,65 @@ protected virtual void OnSetScrollAdjustments (Gtk.Adjustment hadj, Gtk.Adjustme
 {
 }
 
+private class BindingInvoker {
+	System.Reflection.MethodInfo mi;
+	object[] parms;
+
+	public BindingInvoker (System.Reflection.MethodInfo mi, object[] parms)
+	{
+		this.mi = mi;
+		this.parms = parms;
+	}
+
+	public void Invoke (Widget w)
+	{
+		mi.Invoke (w, parms);
+	}
+}
+
+private delegate void BindingHandler (IntPtr handle, IntPtr user_data);
+
+private static void BindingCallback (IntPtr handle, IntPtr user_data)
+{
+	Widget w = GLib.Object.GetObject (handle, false) as Widget;
+	BindingInvoker invoker = ((GCHandle) user_data).Target as BindingInvoker;
+	invoker.Invoke (w);
+}
+
+static BindingHandler binding_delegate;
+static BindingHandler BindingDelegate {
+	get {
+		if (binding_delegate == null)
+			binding_delegate = new BindingHandler (BindingCallback);
+		return binding_delegate;
+	}
+}
+
+[DllImport ("gtksharpglue-2")]
+static extern void gtksharp_widget_add_binding_signal (IntPtr gvalue, string name, BindingHandler handler);
+
+[DllImport ("gtksharpglue-2")]
+static extern void gtksharp_widget_register_binding (IntPtr gvalue, string name, uint key, int mod, IntPtr data);
+
+[GLib.ClassInitializer]
+static void ClassInit (GLib.GType gtype, Type t)
+{
+	object[] attrs = t.GetCustomAttributes (typeof (BindingAttribute), true);
+
+	if (attrs.Length == 0)
+		return;
+
+	string signame = t.Name.Replace (".", "_") + "_bindings";
+
+	gtksharp_widget_add_binding_signal (gtype.Val, signame, BindingDelegate);
+
+	foreach (BindingAttribute attr in attrs) {
+		System.Reflection.MethodInfo mi = t.GetMethod (attr.Handler, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
+		if (mi == null)
+			throw new Exception ("Instance method " + attr.Handler + " not found in " + t);
+
+		BindingInvoker inv = new BindingInvoker (mi, attr.Parms);
+		gtksharp_widget_register_binding (gtype.Val, signame, (uint) attr.Key, (int) attr.Mod, (IntPtr) GCHandle.Alloc (inv));
+	}
+}
+
diff --git a/gtk/glue/widget.c b/gtk/glue/widget.c
index 8b2dda6cb..a235b88d2 100644
--- a/gtk/glue/widget.c
+++ b/gtk/glue/widget.c
@@ -19,6 +19,7 @@
  * Boston, MA 02111-1307, USA.
  */
 
+#include <gtk/gtkbindings.h>
 #include <gtk/gtkwidget.h>
 
 /* Forward declarations */
@@ -35,6 +36,8 @@ void _gtksharp_marshal_VOID__OBJECT_OBJECT (GClosure *closure, GValue *return_va
 int gtksharp_gtk_widget_get_flags (GtkWidget *widget);
 void gtksharp_gtk_widget_set_flags (GtkWidget *widget, int flags);
 int gtksharp_gtk_widget_style_get_int (GtkWidget *widget, const char *name);
+void gtksharp_widget_add_binding_signal (GType gtype, const char *sig_name, GCallback cb);
+void gtksharp_widget_register_binding (GType gtype, const char *sig_name, guint key, int mod, gpointer data);
 /* */
 
 GdkRectangle*
@@ -140,3 +143,20 @@ gtksharp_widget_connect_set_scroll_adjustments_signal (GType gtype, gpointer cb)
 		G_TYPE_NONE, 2, parm_types);
 }
 
+void
+gtksharp_widget_add_binding_signal (GType gtype, const gchar *sig_name, GCallback cb)
+{
+	GType parm_types[] = {G_TYPE_LONG};
+	g_signal_newv (sig_name, gtype, G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, g_cclosure_new (cb, NULL, NULL), NULL, NULL, g_cclosure_marshal_VOID__LONG, G_TYPE_NONE, 1, parm_types);
+}
+
+void
+gtksharp_widget_register_binding (GType gtype, const gchar *signame, guint key, int mod, gpointer data)
+{
+	GObjectClass *klass = g_type_class_peek (gtype);
+	if (klass == NULL)
+		klass = g_type_class_ref (gtype);
+	GtkBindingSet *set = gtk_binding_set_by_class (klass);
+	gtk_binding_entry_add_signal (set, key, mod, signame, 1, G_TYPE_LONG, data);
+}
+
diff --git a/sample/Subclass.cs b/sample/Subclass.cs
index 433787e7a..7ffa85221 100755
--- a/sample/Subclass.cs
+++ b/sample/Subclass.cs
@@ -29,6 +29,11 @@ namespace GtkSamples {
 		}
 	}
 
+	[Binding (Gdk.Key.Escape, "HandleBinding", "Escape")]
+	[Binding (Gdk.Key.Left, "HandleBinding", "Left")]
+	[Binding (Gdk.Key.Right, "HandleBinding", "Right")]
+	[Binding (Gdk.Key.Up, "HandleBinding", "Up")]
+	[Binding (Gdk.Key.Down, "HandleBinding", "Down")]
 	public class MyButton : Gtk.Button {
 
 		public MyButton () : base ("I'm a subclassed button") {}
@@ -37,5 +42,10 @@ namespace GtkSamples {
 		{
 			Console.WriteLine ("Button::Clicked default handler fired.");
 		}
+
+		private void HandleBinding (string text)
+		{
+			Console.WriteLine ("Got a bound keypress: " + text);
+		}
 	}
 }