Merge pull request #26 from dufoli/master

ginterface properties support
This commit is contained in:
Mike Kestner 2011-11-20 21:42:02 -08:00
commit 9d319c8033
7 changed files with 356 additions and 27 deletions

View file

@ -316,7 +316,16 @@ namespace GtkSharp.Generation {
p = (Property) klass.GetProperty (name);
klass = klass.Parent;
}
if (p == null) {
foreach (string iface in interfaces) {
ClassBase igen = SymbolTable.Table.GetClassGen (iface);
if (igen == null)
continue;
p = igen.GetPropertyRecursively (name);
if (p != null)
break;
}
}
return p;
}

View file

@ -107,13 +107,20 @@ namespace GtkSharp.Generation {
sw.WriteLine ();
sw.WriteLine ("\t\tstatic void Initialize (IntPtr ptr, IntPtr data)");
sw.WriteLine ("\t\t{");
sw.WriteLine ("\t\t\tIntPtr ifaceptr = new IntPtr (ptr.ToInt64 () + class_offset);");
sw.WriteLine ("\t\t\t{0} native_iface = ({0}) Marshal.PtrToStructure (ifaceptr, typeof ({0}));", class_struct_name);
foreach (InterfaceVM vm in interface_vms)
sw.WriteLine ("\t\t\tnative_iface." + vm.Name + " = iface." + vm.Name + ";");
sw.WriteLine ("\t\t\tMarshal.StructureToPtr (native_iface, ifaceptr, false);");
sw.WriteLine ("\t\t\tGCHandle gch = (GCHandle) data;");
sw.WriteLine ("\t\t\tgch.Free ();");
if (interface_vms.Count > 0) {
sw.WriteLine ("\t\t\tIntPtr ifaceptr = new IntPtr (ptr.ToInt64 () + class_offset);");
sw.WriteLine ("\t\t\t{0} native_iface = ({0}) Marshal.PtrToStructure (ifaceptr, typeof ({0}));", class_struct_name);
foreach (InterfaceVM vm in interface_vms) {
sw.WriteLine ("\t\t\tnative_iface." + vm.Name + " = iface." + vm.Name + ";");
}
sw.WriteLine ("\t\t\tMarshal.StructureToPtr (native_iface, ifaceptr, false);");
sw.WriteLine ("\t\t\tGCHandle gch = (GCHandle) data;");
sw.WriteLine ("\t\t\tgch.Free ();");
}
foreach (Property prop in props.Values) {
sw.WriteLine ("\t\t\tGLib.Object.OverrideProperty (data, \"" + prop.CName + "\");");
}
sw.WriteLine ("\t\t}");
sw.WriteLine ();
}
@ -309,7 +316,10 @@ namespace GtkSharp.Generation {
vm_table.Remove (vm.Name);
}
}
foreach (Property prop in props.Values) {
sw.WriteLine ("\t\t[GLib.Property (\"" + prop.CName + "\")]");
prop.GenerateDecl (sw, "\t\t");
}
AppendCustom (sw, gen_info.CustomDir, Name + "Implementor");
sw.WriteLine ("\t}");

View file

@ -296,6 +296,14 @@ namespace GLib {
return klass;
}
public IntPtr GetDefaultInterfacePtr ()
{
IntPtr klass = g_type_default_interface_peek (val);
if (klass == IntPtr.Zero)
klass = g_type_default_interface_ref (val);
return klass;
}
public GType GetBaseType ()
{
IntPtr parent = g_type_parent (this.Val);
@ -370,7 +378,7 @@ namespace GLib {
if (gtypes.Contains (t))
return (GType) gtypes [t];
}
PropertyInfo pi = t.GetProperty ("GType", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public);
if (pi != null)
return (GType) pi.GetValue (null, null);
@ -405,6 +413,12 @@ namespace GLib {
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr g_type_class_ref (IntPtr gtype);
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr g_type_default_interface_peek (IntPtr gtype);
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr g_type_default_interface_ref (IntPtr gtype);
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr g_type_from_name (string name);

View file

@ -34,6 +34,7 @@ namespace GLib {
IntPtr handle;
ToggleRef tref;
bool disposed = false;
static uint idx = 1;
static Dictionary<IntPtr, ToggleRef> Objects = new Dictionary<IntPtr, ToggleRef>();
~Object ()
@ -161,6 +162,15 @@ namespace GLib {
}
}
static Dictionary<IntPtr, Dictionary<Type, PropertyInfo>> interface_properties;
static Dictionary<IntPtr, Dictionary<Type, PropertyInfo>> IProperties {
get {
if (interface_properties == null)
interface_properties = new Dictionary<IntPtr, Dictionary<Type, PropertyInfo>> ();
return interface_properties;
}
}
struct GTypeClass {
public IntPtr gtype;
}
@ -230,6 +240,36 @@ namespace GLib {
return raw;
}
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void g_object_class_override_property (IntPtr klass, uint prop_id, IntPtr name);
public static void OverrideProperty (IntPtr declaring_class, string name)
{
IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (name);
g_object_class_override_property (declaring_class, idx, native_name);
idx++;
}
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr g_object_class_find_property (IntPtr klass, IntPtr name);
static IntPtr FindClassProperty (GType type, string name)
{
IntPtr g_iface = type.GetDefaultInterfacePtr ();
IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (name);
return g_object_class_find_property (g_iface, native_name);
}
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr g_object_interface_find_property (IntPtr klass, IntPtr name);
static IntPtr FindInterfaceProperty (GType type, string name)
{
IntPtr g_iface = type.GetDefaultInterfacePtr ();
IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (name);
return g_object_interface_find_property (g_iface, native_name);
}
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void g_object_class_install_property (IntPtr klass, uint prop_id, IntPtr param_spec);
@ -242,10 +282,8 @@ namespace GLib {
return pspec.Handle;
}
static void AddProperties (GType gtype, System.Type t, bool register_instance_prop)
static void AddProperties (GType gtype, System.Type t, bool register_instance_prop, ref bool handlers_overridden)
{
uint idx = 1;
if (register_instance_prop) {
IntPtr declaring_class = gtype.GetClassPtr ();
ParamSpec pspec = new ParamSpec ("gtk-sharp-managed-instance", "", "", GType.Pointer, ParamFlags.Writable | ParamFlags.ConstructOnly);
@ -253,7 +291,6 @@ namespace GLib {
idx++;
}
bool handlers_overridden = register_instance_prop;
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)
@ -305,6 +342,16 @@ namespace GLib {
static void SetPropertyCallback(IntPtr handle, uint property_id, ref GLib.Value value, IntPtr param_spec)
{
// FIXME: Here is a big quick hack to avoid race condition when trying to set up adjustment with contructor
// Because Raw is set too late
if (param_spec != IntPtr.Zero) {
ParamSpec foo = new ParamSpec(param_spec);
if (foo.Name == "gtk-sharp-managed-instance") {
GCHandle gch = (GCHandle) (IntPtr) value.Val;
Object o = (GLib.Object) gch.Target;
o.Raw = handle;
}
}
if (!Properties.ContainsKey (param_spec))
return;
@ -324,17 +371,43 @@ namespace GLib {
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void g_type_add_interface_static (IntPtr gtype, IntPtr iface_type, ref GInterfaceInfo info);
static void AddInterfaces (GType gtype, Type t)
static void AddInterfaces (GType gtype, Type t, ref bool handlers_overridden)
{
foreach (Type iface in t.GetInterfaces ()) {
if (!iface.IsDefined (typeof (GInterfaceAttribute), true) || iface.IsAssignableFrom (t.BaseType))
if (!iface.IsDefined (typeof (GInterfaceAttribute), true))
continue;
GInterfaceAttribute attr = iface.GetCustomAttributes (typeof (GInterfaceAttribute), false) [0] as GInterfaceAttribute;
GInterfaceAdapter adapter = Activator.CreateInstance (attr.AdapterType, null) as GInterfaceAdapter;
GInterfaceInfo info = adapter.Info;
g_type_add_interface_static (gtype.Val, adapter.GType.Val, ref info);
if (!handlers_overridden) {
IntPtr class_ptr = gtype.GetClassPtr ();
GObjectClass gobject_class = (GObjectClass) Marshal.PtrToStructure (class_ptr, typeof (GObjectClass));
gobject_class.get_prop_cb = GetPropertyHandler;
gobject_class.set_prop_cb = SetPropertyHandler;
Marshal.StructureToPtr (gobject_class, class_ptr, false);
handlers_overridden = true;
}
if (!iface.IsAssignableFrom (t.BaseType)) {
GInterfaceInfo info = adapter.Info;
info.Data = gtype.GetClassPtr ();
//FIXME: overiding prop is done inside the init of interface adapter
// not sure that it is the good solution but
// it is the only one I found without exception or loop
g_type_add_interface_static (gtype.Val, adapter.GType.Val, ref info);
}
foreach (PropertyInfo p in iface.GetProperties ()) {
PropertyAttribute[] attrs = p.GetCustomAttributes (typeof (PropertyAttribute), true) as PropertyAttribute [];
if (attrs.Length == 0)
continue;
PropertyAttribute property_attr = attrs [0];
PropertyInfo declared_prop = t.GetProperty (p.Name, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
if (declared_prop == null)
continue;
IntPtr param_spec = FindInterfaceProperty (adapter.GType, property_attr.Name);
Properties [param_spec] = declared_prop;
}
}
}
@ -342,6 +415,7 @@ namespace GLib {
{
GType gtype = GType.RegisterGObjectType (t);
bool is_first_subclass = gtype.GetBaseType () == gtype.GetThresholdType ();
if (is_first_subclass) {
IntPtr class_ptr = gtype.GetClassPtr ();
GObjectClass gobject_class = (GObjectClass) Marshal.PtrToStructure (class_ptr, typeof (GObjectClass));
@ -350,10 +424,12 @@ namespace GLib {
gobject_class.set_prop_cb = SetPropertyHandler;
Marshal.StructureToPtr (gobject_class, class_ptr, false);
}
AddProperties (gtype, t, is_first_subclass);
idx = 1;
bool handlers_overridden = is_first_subclass;
AddProperties (gtype, t, is_first_subclass, ref handlers_overridden);
ConnectDefaultHandlers (gtype, t);
InvokeTypeInitializers (gtype, t);
AddInterfaces (gtype, t);
AddInterfaces (gtype, t, ref handlers_overridden);
return gtype;
}

View file

@ -64,10 +64,11 @@ namespace GLib {
handle = g_param_spec_int64 (p_name, p_nick, p_blurb, Int64.MinValue, Int64.MaxValue, 0, flags);
else if (type == GType.UInt64)
handle = g_param_spec_uint64 (p_name, p_nick, p_blurb, 0, UInt64.MaxValue, 0, flags);
/*
else if (type == GType.Enum)
else if (type == GType.Flags)
* TODO:
else if (type.GetBaseType () == GType.Enum)
handle = g_param_spec_enum (p_name, p_nick, p_blurb, type.Val, (int) (Enum.GetValues((Type)type).GetValue (0)), flags);
/*else if (type == GType.Flags)
* g_param_spec_flags (p_name, p_nick, p_blurb, type.Val, Enum.GetValues((Type)type) [0], flags);
* TODO:
* Both g_param_spec_enum and g_param_spec_flags expect default property values and the members of the enum seemingly cannot be enumerated
*/
else if (type == GType.Float)
@ -85,7 +86,7 @@ namespace GLib {
else if (g_type_is_a (type.Val, GType.Object.Val))
handle = g_param_spec_object (p_name, p_nick, p_blurb, type.Val, flags);
else
throw new ArgumentException ("type");
throw new ArgumentException ("type:" + type.ToString ());
GLib.Marshaller.Free (p_name);
GLib.Marshaller.Free (p_nick);
@ -108,6 +109,21 @@ namespace GLib {
}
}
public string Name {
get {
GParamSpec spec = (GParamSpec) Marshal.PtrToStructure (Handle, typeof (GParamSpec));
return Marshaller.Utf8PtrToString (spec.name);
}
}
public string ToString ()
{
GParamSpec spec = (GParamSpec) Marshal.PtrToStructure (Handle, typeof (GParamSpec));
GType valtype= new GType (spec.value_type);
GType ownertype= new GType (spec.owner_type);
return "ParamSpec: name=" + Marshaller.Utf8PtrToString (spec.name) + " value_type=" + valtype.ToString() + " owner_type=" + ownertype.ToString();
}
struct GTypeInstance {
public IntPtr g_class;
}
@ -136,6 +152,9 @@ namespace GLib {
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr g_param_spec_boolean (IntPtr name, IntPtr nick, IntPtr blurb, bool dval, int flags);
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr g_param_spec_enum (IntPtr name, IntPtr nick, IntPtr blurb, IntPtr enum_type, int dval, int flags);
[DllImport ("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr g_param_spec_int (IntPtr name, IntPtr nick, IntPtr blurb, int min, int max, int dval, int flags);

View file

@ -0,0 +1,197 @@
using GLib;
using Gtk;
using System;
class CustomScrollableWidgetTest {
public static int Main (string[] args)
{
Gtk.Application.Init ();
Window win = new Window ("Custom Scrollable Widget Test");
win.DeleteEvent += new DeleteEventHandler (OnQuit);
ScrolledWindow scroll = new ScrolledWindow ();
scroll.HscrollbarPolicy = PolicyType.Automatic;
scroll.VscrollbarPolicy = PolicyType.Automatic;
CustomScrollableWidget cw = new CustomScrollableWidget ("This one label that is repeated");
scroll.Add (cw);
win.Add (scroll);
win.DefaultWidth = 200;
win.DefaultHeight = 200;
win.ShowAll ();
Gtk.Application.Run ();
return 0;
}
static void OnQuit (object sender, DeleteEventArgs args)
{
Gtk.Application.Quit ();
}
}
abstract class CustomBase : Widget
{
public CustomBase () : base ()
{ }
}
class CustomScrollableWidget : CustomBase, ScrollableImplementor {
private int num_rows = 20;
private string label;
private Pango.Layout layout;
public CustomScrollableWidget (string custom_label) : base ()
{
label = custom_label;
layout = null;
HasWindow = false;
}
private Pango.Layout Layout {
get {
if (layout == null)
layout = CreatePangoLayout (label);
return layout;
}
}
private Gdk.Rectangle ContentArea {
get {
Gdk.Rectangle area;
area.X = Allocation.X;
area.Y = Allocation.Y;
int layoutWidth, layoutHeight;
Layout.GetPixelSize (out layoutWidth, out layoutHeight);
area.Width = layoutWidth;
area.Height = layoutHeight * num_rows;
return area;
}
}
protected override bool OnDrawn (Cairo.Context cr)
{
int layout_x = - HadjustmentValue;
int layout_y = - VadjustmentValue;
int layoutWidth, layoutHeight;
Layout.GetPixelSize (out layoutWidth, out layoutHeight);
for (int i = 0; i < num_rows; i++) {
Layout.SetText (String.Format ("{0} {1}", label, i));
StyleContext.RenderLayout (cr, layout_x, layout_y, Layout);
layout_y += layoutHeight;
}
return base.OnDrawn (cr);
}
protected override void OnSizeAllocated (Gdk.Rectangle allocation)
{
base.OnSizeAllocated (allocation);
if (hadjustment != null) {
hadjustment.PageSize = allocation.Width;
hadjustment.PageIncrement = allocation.Width;
UpdateAdjustments ();
}
if (vadjustment != null) {
vadjustment.PageSize = allocation.Height;
vadjustment.PageIncrement = allocation.Height;
UpdateAdjustments ();
}
}
private Adjustment hadjustment;
public Adjustment Hadjustment {
get { return hadjustment; }
set {
if (value == hadjustment) {
return;
}
hadjustment = value;
if (hadjustment == null) {
return;
}
hadjustment.ValueChanged += OnHadjustmentChanged;
UpdateAdjustments ();
}
}
private Adjustment vadjustment;
public Adjustment Vadjustment {
get { return vadjustment; }
set {
if (value == vadjustment) {
return;
}
vadjustment = value;
if (vadjustment == null) {
return;
}
vadjustment.ValueChanged += OnVadjustmentChanged;
UpdateAdjustments ();
}
}
private int HadjustmentValue {
get { return hadjustment == null ? 0 : (int)hadjustment.Value; }
}
private int VadjustmentValue {
get { return vadjustment == null ? 0 : (int)vadjustment.Value; }
}
public Gtk.ScrollablePolicy HscrollPolicy {
get; set;
}
public Gtk.ScrollablePolicy VscrollPolicy {
get; set;
}
private void UpdateAdjustments ()
{
int layoutWidth, layoutHeight;
Layout.GetPixelSize (out layoutWidth, out layoutHeight);
if (hadjustment != null) {
hadjustment.Upper = ContentArea.Width;
hadjustment.StepIncrement = 10.0;
if (hadjustment.Value + hadjustment.PageSize > hadjustment.Upper) {
hadjustment.Value = hadjustment.Upper - hadjustment.PageSize;
}
Console.WriteLine (String.Format ("H adj={0} upper={1} PageSize={2} PageInc={3}",
HadjustmentValue, hadjustment.Upper, hadjustment.PageSize, hadjustment.PageIncrement));
hadjustment.Change ();
}
if (vadjustment != null) {
vadjustment.Upper = ContentArea.Height;
vadjustment.StepIncrement = layoutHeight;
if (vadjustment.Value + vadjustment.PageSize > vadjustment.Upper) {
vadjustment.Value = vadjustment.Upper - vadjustment.PageSize;
}
Console.WriteLine (String.Format ("V adj={0} upper={1} PageSize={2} PageInc={3}",
VadjustmentValue, vadjustment.Upper, vadjustment.PageSize, vadjustment.PageIncrement));
vadjustment.Change ();
}
}
private void OnHadjustmentChanged (object o, EventArgs args)
{
UpdateAdjustments ();
QueueDraw ();
}
private void OnVadjustmentChanged (object o, EventArgs args)
{
UpdateAdjustments ();
QueueDraw ();
}
}

View file

@ -8,7 +8,7 @@ DOTNET_TARGETS=
DOTNET_ASSEMBLY=
endif
TARGETS = gtk-hello-world.exe button.exe calendar.exe subclass.exe menu.exe treeviewdemo.exe managedtreeviewdemo.exe nodeviewdemo.exe treemodeldemo.exe actions.exe spawn.exe assistant.exe registerprop.exe gexceptiontest.exe native-instantiation.exe polarfixed.exe cairo-sample.exe scribble.exe testdnd.exe custom-cellrenderer.exe custom-widget.exe #scribble-xinput.exe $(DOTNET_TARGETS)
TARGETS = gtk-hello-world.exe button.exe calendar.exe subclass.exe menu.exe treeviewdemo.exe managedtreeviewdemo.exe nodeviewdemo.exe treemodeldemo.exe actions.exe spawn.exe assistant.exe registerprop.exe gexceptiontest.exe native-instantiation.exe polarfixed.exe cairo-sample.exe scribble.exe testdnd.exe custom-cellrenderer.exe custom-widget.exe custom-scrollable.exe #scribble-xinput.exe $(DOTNET_TARGETS)
DEBUGS = $(addsuffix .mdb, $(TARGETS))
@ -79,6 +79,9 @@ drawing-sample.exe: $(srcdir)/DrawingSample.cs $(assemblies) $(DOTNET_ASSEMBLIES
custom-widget.exe: $(srcdir)/CustomWidget.cs $(assemblies)
$(CSC) $(CSFLAGS) -out:custom-widget.exe $(references) $(srcdir)/CustomWidget.cs
custom-scrollable.exe: $(srcdir)/CustomScrollableWidget.cs $(assemblies)
$(CSC) $(CSFLAGS) -out:custom-scrollable.exe $(references) $(srcdir)/CustomScrollableWidget.cs
actions.exe: $(srcdir)/Actions.cs
$(CSC) $(CSFLAGS) -unsafe -out:actions.exe $(references) $(srcdir)/Actions.cs
@ -118,6 +121,7 @@ EXTRA_DIST = \
CustomCellRenderer.cs \
DrawingSample.cs \
CustomWidget.cs \
CustomScrollableWidget.cs \
Actions.cs \
PropertyRegistration.cs \
PolarFixed.cs