2008-06-06 Mike Kestner <mkestner@novell.com>

Initial Patch submitted by Christian Hoff with some small
	style alterations and a round trip sample by me.  Supports the 
	registration of managed properties with the GType system, so 
	that things like custom cell renderers can be accessed via the
	native property system from treeview.

	* glib/glue/object.c : property registration related glue.
	* glib/Object.cs: implement managed property registration.
	* glib/PropertyAttribute.cs: add new props and ctor for managed
	property registration.
	* sample/PropertyRegistration.cs: little test app to test round-
	tripping of registered properties.
	* sample/Makefile.am: add new sample.

svn path=/trunk/gtk-sharp/; revision=105177
This commit is contained in:
Mike Kestner 2008-06-06 16:55:00 +00:00
parent 7d9723862d
commit 9864a0960d
6 changed files with 276 additions and 1 deletions

View File

@ -1,3 +1,19 @@
2008-06-06 Mike Kestner <mkestner@novell.com>
Initial Patch submitted by Christian Hoff with some small
style alterations and a round trip sample by me. Supports the
registration of managed properties with the GType system, so
that things like custom cell renderers can be accessed via the
native property system from treeview.
* glib/glue/object.c : property registration related glue.
* glib/Object.cs: implement managed property registration.
* glib/PropertyAttribute.cs: add new props and ctor for managed
property registration.
* sample/PropertyRegistration.cs: little test app to test round-
tripping of registered properties.
* sample/Makefile.am: add new sample.
2008-06-06 Mike Kestner <mkestner@novell.com>
* atk/Object.custom: use 'as StateSet' instead of cast to avoid

View File

@ -173,6 +173,95 @@ namespace GLib {
minfo.Invoke (null, parms);
}
}
// Key: The pointer to the ParamSpec of the property
// Value: The corresponding PropertyInfo object
static Hashtable properties;
static Hashtable Properties {
get {
if (properties == null)
properties = new Hashtable ();
return properties;
}
}
[DllImport ("glibsharpglue-2")]
static extern void gtksharp_override_property_handlers (IntPtr type, GetPropertyDelegate get_cb, SetPropertyDelegate set_cb);
[DllImport ("glibsharpglue-2")]
static extern IntPtr gtksharp_register_property (IntPtr type, IntPtr name, IntPtr nick, IntPtr blurb, uint property_id, IntPtr property_type, bool can_read, bool can_write);
static void AddProperties (GType gtype, System.Type t)
{
uint idx = 1;
bool handlers_overridden = false;
foreach (PropertyInfo pinfo in t.GetProperties (BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)) {
foreach (object attr in pinfo.GetCustomAttributes (typeof (PropertyAttribute), false)) {
if(pinfo.GetIndexParameters().Length > 0)
throw(new InvalidOperationException(String.Format("GLib.RegisterPropertyAttribute cannot be applied to property {0} of type {1} because the property expects one or more indexed parameters", pinfo.Name, t.FullName)));
PropertyAttribute property_attr = attr as PropertyAttribute;
if (!handlers_overridden) {
gtksharp_override_property_handlers (gtype.Val, GetPropertyHandler, SetPropertyHandler);
handlers_overridden = true;
}
IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (property_attr.Name);
IntPtr native_nick = GLib.Marshaller.StringToPtrGStrdup (property_attr.Nickname);
IntPtr native_blurb = GLib.Marshaller.StringToPtrGStrdup (property_attr.Blurb);
IntPtr param_spec = gtksharp_register_property (gtype.Val, native_name, native_nick, native_blurb, idx, ((GType) pinfo.PropertyType).Val, pinfo.CanRead, pinfo.CanWrite);
GLib.Marshaller.Free (native_name);
GLib.Marshaller.Free (native_nick);
GLib.Marshaller.Free (native_blurb);
if (param_spec == IntPtr.Zero)
// The GType of the property is not supported
throw new InvalidOperationException (String.Format ("GLib.PropertyAttribute cannot be applied to property {0} of type {1} because the return type of the property is not supported", pinfo.Name, t.FullName));
Properties.Add (param_spec, pinfo);
idx++;
}
}
}
[GLib.CDeclCallback]
delegate void GetPropertyDelegate (IntPtr GObject, uint property_id, ref GLib.Value value, IntPtr pspec);
static void GetPropertyCallback (IntPtr handle, uint property_id, ref GLib.Value value, IntPtr param_spec)
{
GLib.Object obj = GLib.Object.GetObject (handle, false);
value.Val = (Properties [param_spec] as PropertyInfo).GetValue (obj, new object [0]);
}
static GetPropertyDelegate get_property_handler;
static GetPropertyDelegate GetPropertyHandler {
get {
if (get_property_handler == null)
get_property_handler = new GetPropertyDelegate (GetPropertyCallback);
return get_property_handler;
}
}
[GLib.CDeclCallback]
delegate void SetPropertyDelegate (IntPtr GObject, uint property_id, ref GLib.Value value, IntPtr pspec);
static void SetPropertyCallback(IntPtr handle, uint property_id, ref GLib.Value value, IntPtr param_spec)
{
GLib.Object obj = GLib.Object.GetObject (handle, false);
(Properties [param_spec] as PropertyInfo).SetValue (obj, value.Val, new object [0]);
}
static SetPropertyDelegate set_property_handler;
static SetPropertyDelegate SetPropertyHandler {
get {
if (set_property_handler == null)
set_property_handler = new SetPropertyDelegate (SetPropertyCallback);
return set_property_handler;
}
}
[DllImport("libgobject-2.0-0.dll")]
static extern void g_type_add_interface_static (IntPtr gtype, IntPtr iface_type, ref GInterfaceInfo info);
@ -227,6 +316,7 @@ namespace GLib {
GType gtype = new GType (gtksharp_register_type (native_name, parent_gtype.Val));
GLib.Marshaller.Free (native_name);
GLib.GType.Register (gtype, t);
AddProperties (gtype, t);
ConnectDefaultHandlers (gtype, t);
InvokeClassInitializers (gtype, t);
AddInterfaces (gtype, t);

View File

@ -22,6 +22,9 @@ namespace GLib {
using System;
public sealed class PropertyAttribute : Attribute {
string blurb;
string nickname;
string name;
public PropertyAttribute (string name)
@ -29,6 +32,22 @@ namespace GLib {
this.name = name;
}
public PropertyAttribute (string name, string nickname, string blurb)
{
this.name = name;
this.nickname = nickname;
this.blurb = blurb;
}
public string Blurb {
get {
return blurb;
}
set {
blurb = value;
}
}
public string Name {
get {
return name;
@ -37,5 +56,14 @@ namespace GLib {
name = value;
}
}
public string Nickname {
get {
return nickname;
}
set {
nickname = value;
}
}
}
}

View File

@ -24,6 +24,8 @@
/* Forward declarations */
int gtksharp_object_get_ref_count (GObject *obj);
GObject *gtksharp_object_newv (GType type, gint cnt, gchar **names, GValue *vals);
void gtksharp_override_property_handlers(GType type, gpointer get_property_cb, gpointer set_property_cb);
GParamSpec *gtksharp_register_property(GType declaring_type, const gchar *name, const gchar *nick, const gchar *blurb, guint id, GType return_type, gboolean can_read, gboolean can_write);
/* */
int
@ -53,3 +55,94 @@ gtksharp_object_newv (GType type, gint cnt, gchar **names, GValue *vals)
return result;
}
void
gtksharp_override_property_handlers(GType type, gpointer get_property_cb, gpointer set_property_cb)
{
GObjectClass *type_class = g_type_class_peek (type);
if(!type_class)
type_class = g_type_class_ref (type);
type_class->get_property = get_property_cb;
type_class->set_property = set_property_cb;
}
GParamSpec *
gtksharp_register_property(GType declaring_type, const gchar *name, const gchar *nick, const gchar *blurb, guint id, GType return_type, gboolean can_read, gboolean can_write)
{
GParamSpec *param_spec;
GParamFlags flags = 0;
GObjectClass *declaring_class = g_type_class_peek (declaring_type);
if (!declaring_class)
declaring_class = g_type_class_ref (declaring_type);
if (can_read)
flags |= G_PARAM_READABLE;
if (can_write)
flags |= G_PARAM_WRITABLE;
/* Create the ParamSpec for the property
* These are used to hold default values and to validate values
* Both is not needed since the check for invalid values takes place in the managed set accessor of the property and properties do not
* contain default values. Therefore the ParamSpecs must allow every value that can be assigned to the property type.
* Furthermore the default value that is specified in the constructors will never be used and assigned to the property;
* they are not relevant, but have to be passed
*/
switch (return_type) {
case G_TYPE_CHAR:
param_spec = g_param_spec_char (name, nick, blurb, G_MININT8, G_MAXINT8, 0, flags);
break;
case G_TYPE_UCHAR:
param_spec = g_param_spec_uchar (name, nick, blurb, 0, G_MAXUINT8, 0, flags);
break;
case G_TYPE_BOOLEAN:
param_spec = g_param_spec_boolean (name, nick, blurb, FALSE, flags);
break;
case G_TYPE_INT:
param_spec = g_param_spec_int (name, nick, blurb, G_MININT, G_MAXINT, 0, flags);
break;
case G_TYPE_UINT:
param_spec = g_param_spec_uint (name, nick, blurb, 0, G_MAXUINT, 0, flags);
break;
case G_TYPE_LONG:
param_spec = g_param_spec_long (name, nick, blurb, G_MINLONG, G_MAXLONG, 0, flags);
break;
case G_TYPE_ULONG:
param_spec = g_param_spec_ulong (name, nick, blurb, 0, G_MAXULONG, 0, flags);
break;
case G_TYPE_INT64:
param_spec = g_param_spec_int64 (name, nick, blurb, G_MININT64, G_MAXINT64, 0, flags);
break;
case G_TYPE_UINT64:
param_spec = g_param_spec_uint64 (name, nick, blurb, 0, G_MAXUINT64, 0, flags);
break;
/* case G_TYPE_ENUM:
* case G_TYPE_FLAGS:
* TODO: Implement both G_TYPE_ENUM and G_TYPE_FLAGS
* My problem: Both g_param_spec_enum and g_param_spec_flags expect default property values and the members of the enum seemingly cannot be enumerated
*/
case G_TYPE_FLOAT:
param_spec = g_param_spec_float (name, nick, blurb, G_MINFLOAT, G_MAXFLOAT, 0, flags);
break;
case G_TYPE_DOUBLE:
param_spec = g_param_spec_double (name, nick, blurb, G_MINDOUBLE, G_MAXDOUBLE, 0, flags);
break;
case G_TYPE_STRING:
param_spec = g_param_spec_string (name, nick, blurb, NULL, flags);
break;
case G_TYPE_POINTER:
param_spec = g_param_spec_pointer (name, nick, blurb, flags);
break;
case G_TYPE_BOXED:
param_spec = g_param_spec_boxed (name, nick, blurb, return_type, flags);
break;
case G_TYPE_OBJECT:
param_spec = g_param_spec_object (name, nick, blurb, return_type, flags);
break;
default:
// The property's return type is not supported
return NULL;
}
g_object_class_install_property (declaring_class, id, param_spec);
return param_spec;
}

View File

@ -16,7 +16,7 @@ DOTNET_TARGETS=
DOTNET_ASSEMBLY=
endif
TARGETS = polarfixed.exe custom-widget.exe custom-cellrenderer.exe gtk-hello-world.exe button.exe calendar.exe subclass.exe menu.exe size.exe scribble.exe scribble-xinput.exe treeviewdemo.exe managedtreeviewdemo.exe nodeviewdemo.exe treemodeldemo.exe testdnd.exe actions.exe spawn.exe assistant.exe $(GLADE_TARGETS) $(DOTNET_TARGETS)
TARGETS = polarfixed.exe custom-widget.exe custom-cellrenderer.exe gtk-hello-world.exe button.exe calendar.exe subclass.exe menu.exe size.exe scribble.exe scribble-xinput.exe treeviewdemo.exe managedtreeviewdemo.exe nodeviewdemo.exe treemodeldemo.exe testdnd.exe actions.exe spawn.exe assistant.exe registerprop.exe $(GLADE_TARGETS) $(DOTNET_TARGETS)
DEBUGS = $(addsuffix .mdb, $(TARGETS))
@ -97,6 +97,9 @@ spawn.exe: $(srcdir)/SpawnTests.cs $(assemblies)
assistant.exe: $(srcdir)/Assistant.cs $(assemblies)
$(CSC) /out:assistant.exe $(references) $(srcdir)/Assistant.cs
registerprop.exe: $(srcdir)/PropertyRegistration.cs $(assemblies)
$(CSC) /out:registerprop.exe $(references) $(srcdir)/PropertyRegistration.cs
EXTRA_DIST = \
HelloWorld.cs \
Assistant.cs \
@ -122,5 +125,6 @@ EXTRA_DIST = \
cairo-sample.exe.config \
CustomWidget.cs \
Actions.cs \
PropertyRegistration.cs \
PolarFixed.cs

View File

@ -0,0 +1,44 @@
// PropertyRegistration.cs - GObject property registration sample
//
// Author: Mike Kestner <mkestner@novell.com>
//
// Copyright (c) 2008 Novell, Inc.
namespace GtkSamples {
using System;
public class TestObject : GLib.Object {
public static int Main (string[] args)
{
GLib.GType.Init ();
TestObject obj = new TestObject ();
GLib.Value val = new GLib.Value (42);
obj.SetProperty ("my_prop", val);
val.Dispose ();
if (obj.MyProp != 42) {
Console.Error.WriteLine ("Property setter did not run.");
return 1;
}
GLib.Value val2 = obj.GetProperty ("my_prop");
if ((int)val2.Val != 42) {
Console.Error.WriteLine ("Property set/get roundtrip failed.");
return 1;
}
Console.WriteLine ("Round trip succeeded.");
return 0;
}
int my_prop;
[GLib.Property ("my_prop")]
public int MyProp {
get { return my_prop; }
set {
my_prop = value;
Console.WriteLine ("Property setter invoked.");
}
}
}
}