From adef5f7bbdd417e03f2fc402961b435b951eba46 Mon Sep 17 00:00:00 2001 From: Mike Kestner Date: Thu, 23 Dec 2004 22:59:59 +0000 Subject: [PATCH] 2004-12-23 Mike Kestner * 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. svn path=/trunk/gtk-sharp/; revision=38074 --- ChangeLog | 12 +++ doc/ChangeLog | 5 + doc/en/GLib/ClassInitializerAttribute.xml | 33 ++++++ doc/en/Gtk/BindingAttribute.xml | 116 ++++++++++++++++++++++ glib/ClassInitializerAttribute.cs | 30 ++++++ glib/Makefile.am | 1 + glib/Object.cs | 15 ++- gtk/BindingAttribute.cs | 68 +++++++++++++ gtk/Makefile.am | 1 + gtk/Widget.custom | 62 ++++++++++++ gtk/glue/widget.c | 20 ++++ sample/Subclass.cs | 10 ++ 12 files changed, 369 insertions(+), 4 deletions(-) create mode 100644 doc/en/GLib/ClassInitializerAttribute.xml create mode 100644 doc/en/Gtk/BindingAttribute.xml create mode 100644 glib/ClassInitializerAttribute.cs create mode 100644 gtk/BindingAttribute.cs diff --git a/ChangeLog b/ChangeLog index 2cde164ef..92fdbec57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2004-12-23 Mike Kestner + + * 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 * 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 + + * en/GLib/ClassInitializerAttribute.xml : doc new attr. + * en/Gtk/BindingAttribute.xml : doc new attr. + 2004-12-22 Dan Winship * 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 @@ + + + + glib-sharp + [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] + 2.0.0.0 + neutral + + + Gtk# is thread aware, but not thread safe; See the Gtk# Thread Programming for details. + + Identifies a class initialization method to call when GTypes are registered. + + + + System.Attribute + + + + + + + Constructor + + + + Constructs an attribute. + a + + + + + 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 @@ + + + + gtk-sharp + [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] + 2.0.0.0 + neutral + + + Gtk# is thread aware, but not thread safe; See the Gtk# Thread Programming for details. + + Registers a key binding for a class. + + + + System.Attribute + + + + + System.AttributeUsageAttribute + + + + + + Constructor + + + + + + + + Constructs a Binding attribute with no key modifier. + a key value + name of the instance method to call. + an array containing the parameters to pass to the handler. + a + + + + + + Constructor + + + + + + + + + Constructs a Binding attribute for a key and modifier. + a key value + a modifier type, like ctrl or shift + name of the instance method to call. + an array containing the parameters to pass to the handler. + a + + + + + + Property + + Gdk.Key + + + + The key value + a + + + + + + Property + + Gdk.ModifierType + + + + The key modifier, such as ctrl or shift. + a + + + + + + Property + + System.String + + + + The name of the instance method to call on activation. + a + + + + + + Property + + System.Object[] + + + + An Array of parameters to pass to the Handler. + a + + + + + 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 +// +// 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 +// +// 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 #include /* 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); + } } }