diff --git a/ChangeLog b/ChangeLog index f7945bfed..e360dce06 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2004-05-07 Mike Kestner + + [Derived from a patch by Ben Maurer] + * generator/Ctor.cs : generate code to detect subclassing and handle + GType registration and native object creation properly. + * generator/Parameters.cs : add PropertyName accessor for param attr. + * generator/Property.cs : use a new GLib.Value ctor. + * glib/ObjectManager.cs : redo hash access. + * glib/Object.cs : CreateNativeObject method to invoke g_object_newv + and some refactoring of RegisterGType and LookupGType. + * glib/Value.cs : make gtype field an IntPtr. + * glib/glue/object.c : glue for g_object_newv use. + * glib/glue/value.c : new glue for value creation. + * gtk/Dialog.custom : fix a ctor declaration for auto-reg. + * gtk/Gtk.metadata : mark a couple property_name attrs as examples. + * sample/Subclass.cs : use auto-GType-registration now. + 2004-05-06 Mike Kestner * gdk/Gdk.metadata : some out and array magic for Property.Get. diff --git a/generator/Ctor.cs b/generator/Ctor.cs index 7fd2258d7..198833513 100644 --- a/generator/Ctor.cs +++ b/generator/Ctor.cs @@ -23,6 +23,7 @@ namespace GtkSharp.Generation { private string clashName = null; private ClassBase container_type; private bool force_static; + private bool needs_chaining = false; public bool Preferred { get { return preferred; } @@ -47,6 +48,8 @@ namespace GtkSharp.Generation { parms = new Parameters (parms_elem, container_type.NS); if (elem.HasAttribute ("preferred")) preferred = true; + if (container_type is ObjectGen) + needs_chaining = true; } public bool Validate () @@ -102,6 +105,8 @@ namespace GtkSharp.Generation { else safety = ""; + SymbolTable table = SymbolTable.Table; + sw.WriteLine("\t\t[DllImport(\"" + libname + "\")]"); sw.WriteLine("\t\tstatic extern " + safety + "IntPtr " + cname + "(" + isig.ToString () + ");"); sw.WriteLine(); @@ -133,9 +138,60 @@ namespace GtkSharp.Generation { sw.Write ("new {0} (", name); sw.WriteLine (cname + "(" + body.GetCallString (false) + "));"); } else { - sw.WriteLine("\t\tpublic " + safety + name + "(" + sig.ToString() + ") : base (IntPtr.Zero)"); + sw.WriteLine("\t\tpublic {0}{1} ({2}) {3}", safety, name, sig.ToString(), needs_chaining ? ": base (IntPtr.Zero)" : ""); sw.WriteLine("\t\t{"); + if (needs_chaining) { + sw.WriteLine ("\t\t\tif (GetType () != typeof (" + name + ")) {"); + + if (Params == null || Params.Count == 0) { + sw.WriteLine ("\t\t\t\tCreateNativeObject (new string [0], new GLib.Value[0]);"); + sw.WriteLine ("\t\t\t\treturn;"); + } else { + ArrayList names = new ArrayList (); + ArrayList values = new ArrayList (); + for (int i = 0; i < Params.Count; i++) { + Parameter p = Params[i]; + if (container_type.GetPropertyRecursively (p.StudlyName) != null) { + names.Add (p.Name); + values.Add (p.Name); + } else if (p.PropertyName != String.Empty) { + names.Add (p.PropertyName); + values.Add (p.Name); + } + } + + if (names.Count == Params.Count) { + sw.WriteLine ("\t\t\t\tArrayList vals = new ArrayList();"); + sw.WriteLine ("\t\t\t\tArrayList names = new ArrayList();"); + for (int i = 0; i < names.Count; i++) { + Parameter p = Params [i]; + string indent = "\t\t\t\t"; + if (p.NullOk && p.Generatable is ObjectGen) { + sw.WriteLine (indent + "if (" + p.Name + " != null) {"); + indent += "\t"; + } + sw.WriteLine (indent + "names.Add (\"" + names [i] + "\");"); + sw.Write (indent + "vals.Add ("); + + if (table.IsEnum (p.CType)) + sw.WriteLine ("new GLib.Value (this, \"" + names[i] + "\", new GLib.EnumWrapper ((int)" + values[i] + ", " + (table.IsEnumFlags (p.CType) ? "true" : "false") + ")));"); + else + sw.WriteLine ("new GLib.Value (" + values[i] + "));"); + + if (p.NullOk && p.Generatable is ObjectGen) + sw.WriteLine ("\t\t\t\t}"); + } + + sw.WriteLine ("\t\t\t\tCreateNativeObject ((string[])names.ToArray (typeof (string)), (GLib.Value[])vals.ToArray (typeof (GLib.Value)));"); + sw.WriteLine ("\t\t\t\treturn;"); + } else + sw.WriteLine ("\t\t\t\tthrow new InvalidOperationException (\"Can't override this constructor.\");"); + } + + sw.WriteLine ("\t\t\t}"); + } + body.Initialize(gen_info, false, false, ""); sw.WriteLine("\t\t\t{0} = {1}({2});", container_type.AssignToName, cname, body.GetCallString (false)); body.HandleException (sw, ""); diff --git a/generator/Parameters.cs b/generator/Parameters.cs index 01c0fa13c..b3fa955c2 100644 --- a/generator/Parameters.cs +++ b/generator/Parameters.cs @@ -145,6 +145,12 @@ namespace GtkSharp.Generation { } } + public string PropertyName { + get { + return elem.GetAttribute("property_name"); + } + } + public string PassAs { get { if (elem.HasAttribute ("pass_as")) @@ -195,7 +201,6 @@ namespace GtkSharp.Generation { } } - } public class Parameters { diff --git a/generator/Property.cs b/generator/Property.cs index fc1ae4060..f80128620 100644 --- a/generator/Property.cs +++ b/generator/Property.cs @@ -162,7 +162,7 @@ namespace GtkSharp.Generation { sw.WriteLine("\t\t\tset {"); sw.Write("\t\t\t\tGLib.Value val = "); if (table.IsEnum(c_type)) { - sw.WriteLine("new GLib.Value(Handle, " + cname + ", new GLib.EnumWrapper ((int) value, {0}));", table.IsEnumFlags (c_type) ? "true" : "false"); + sw.WriteLine("new GLib.Value(this, " + cname + ", new GLib.EnumWrapper ((int) value, {0}));", table.IsEnumFlags (c_type) ? "true" : "false"); } else if (table.IsBoxed (c_type)) { sw.WriteLine("(GLib.Value) value;"); } else if (table.IsOpaque (c_type)) { diff --git a/glib/Object.cs b/glib/Object.cs index e074a6f1e..ec6c00c3b 100644 --- a/glib/Object.cs +++ b/glib/Object.cs @@ -127,15 +127,9 @@ namespace GLib { public static GType RegisterGType (System.Type t) { - System.Type parent = t.BaseType; - PropertyInfo pi = parent.GetProperty ("GType", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public); - if (pi == null) { - Console.WriteLine ("null PropertyInfo"); - return GType.Invalid; - } - GType parent_gtype = (GType) pi.GetValue (null, null); - string name = t.Namespace.Replace(".", "_") + t.Name; - GtkSharp.ObjectManager.RegisterType (name, t.Namespace + t.Name, t.Assembly.GetName().Name); + GType parent_gtype = LookupGType (t.BaseType); + string name = t.FullName.Replace(".", "_"); + GtkSharp.ObjectManager.RegisterType (name, t.FullName, t.Assembly.GetName().Name); GType gtype = new GType (gtksharp_register_type (name, parent_gtype.Val)); ConnectDefaultHandlers (gtype, t); g_types[t] = gtype; @@ -144,9 +138,15 @@ namespace GLib { static Hashtable g_types = new Hashtable (); - public static GType GetGType (System.Type t) + + public GType LookupGType () { - if (g_types.ContainsKey (t)) + return LookupGType (GetType ()); + } + + private static GType LookupGType (System.Type t) + { + if (g_types.Contains (t)) return (GType) g_types [t]; PropertyInfo pi = t.GetProperty ("GType", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public); @@ -169,6 +169,14 @@ namespace GLib { Raw = g_object_new (gtype.Val, IntPtr.Zero); } + [DllImport("glibsharpglue")] + static extern IntPtr gtksharp_object_newv (IntPtr gtype, int n_params, string[] names, GLib.Value[] vals); + + protected void CreateNativeObject (string[] names, GLib.Value[] vals) + { + Raw = gtksharp_object_newv (LookupGType ().Val, names.Length, names, vals); + } + protected virtual IntPtr Raw { get { return _obj; diff --git a/glib/ObjectManager.cs b/glib/ObjectManager.cs index b89860dcb..22f8ac05c 100644 --- a/glib/ObjectManager.cs +++ b/glib/ObjectManager.cs @@ -45,12 +45,12 @@ namespace GtkSharp { public static void RegisterType (string native_name, string managed_name, string assembly) { - types.Add(native_name, managed_name + "," + assembly); + RegisterType (native_name, managed_name + "," + assembly); } public static void RegisterType (string native_name, string mangled) { - types.Add(native_name, mangled); + types [native_name] = mangled; } static string GetExpected (string cname) diff --git a/glib/Value.cs b/glib/Value.cs index 9d9195f55..ef387bd70 100755 --- a/glib/Value.cs +++ b/glib/Value.cs @@ -15,7 +15,7 @@ namespace GLib { [StructLayout (LayoutKind.Sequential)] public struct Value : IDisposable { - GType type; + IntPtr type; long pad_1; long pad_2; @@ -30,6 +30,9 @@ namespace GLib { [DllImport("glibsharpglue")] static extern IntPtr gtksharp_value_create_from_property(ref GLib.Value val, IntPtr obj, string name); + [DllImport("glibsharpglue")] + static extern IntPtr gtksharp_value_create_from_type_and_property(ref GLib.Value val, IntPtr gtype, string name); + public void Dispose () { g_value_unset (ref this); @@ -42,14 +45,14 @@ namespace GLib { public Value (GLib.GType gtype) { - type = GType.Invalid; + type = IntPtr.Zero; pad_1 = pad_2 = 0; g_value_init (ref this, gtype.Val); } public Value (GLib.Object obj, string prop_name) { - type = GType.Invalid; + type = IntPtr.Zero; pad_1 = pad_2 = 0; gtksharp_value_create_from_property (ref this, obj.Handle, prop_name); } @@ -81,7 +84,7 @@ namespace GLib { public Value (IntPtr obj, string prop_name, Opaque val) { - type = GType.Invalid; + type = IntPtr.Zero; pad_1 = pad_2 = 0; gtksharp_value_create_from_property (ref this, obj, prop_name); g_value_set_boxed (ref this, val.Handle); @@ -155,11 +158,11 @@ namespace GLib { [DllImport("libgobject-2.0-0.dll")] static extern void g_value_set_char (ref Value val, char data); - public Value (IntPtr obj, string prop_name, EnumWrapper wrap) + public Value (GLib.Object obj, string prop_name, EnumWrapper wrap) { - type = GType.Invalid; + type = IntPtr.Zero; pad_1 = pad_2 = 0; - gtksharp_value_create_from_property (ref this, obj, prop_name); + gtksharp_value_create_from_type_and_property (ref this, obj.LookupGType ().Val, prop_name); if (wrap.flags) g_value_set_flags (ref this, (uint) (int) wrap); else @@ -168,7 +171,7 @@ namespace GLib { public Value (object obj) { - type = GType.Invalid; + type = IntPtr.Zero; pad_1 = pad_2 = 0; GType gtype = TypeConverter.LookupType (obj.GetType ()); diff --git a/glib/glue/object.c b/glib/glue/object.c index 83ba38ed7..e222111ba 100644 --- a/glib/glue/object.c +++ b/glib/glue/object.c @@ -9,6 +9,7 @@ /* Forward declarations */ int gtksharp_object_get_ref_count (GObject *obj); +GObject *gtksharp_object_newv (GType type, gint cnt, gchar **names, GValue *vals); /* */ int @@ -16,3 +17,25 @@ gtksharp_object_get_ref_count (GObject *obj) { return obj->ref_count; } + +GObject * +gtksharp_object_newv (GType type, gint cnt, gchar **names, GValue *vals) +{ + int i; + GParameter *parms = NULL; + GObject *result; + + if (cnt > 0) + parms = g_new0 (GParameter, cnt); + + for (i = 0; i < cnt; i++) { + parms[i].name = names[i]; + parms[i].value = vals[i]; + } + + result = g_object_newv (type, cnt, parms); + + g_free (parms); + return result; +} + diff --git a/glib/glue/value.c b/glib/glue/value.c index 2d808bc99..e7eddc088 100644 --- a/glib/glue/value.c +++ b/glib/glue/value.c @@ -9,6 +9,7 @@ /* Forward declarations */ void gtksharp_value_create_from_property (GValue *value, GObject *obj, const gchar* name); +void gtksharp_value_create_from_type_and_property (GValue *value, GType gtype, const gchar* name); GType gtksharp_value_get_value_type (GValue *value); gpointer glibsharp_value_get_boxed (GValue *value); void glibsharp_value_set_boxed (GValue *value, gpointer boxed); @@ -21,6 +22,13 @@ gtksharp_value_create_from_property (GValue *value, GObject *obj, const gchar* n g_value_init (value, spec->value_type); } +void +gtksharp_value_create_from_type_and_property (GValue *value, GType gtype, const gchar* name) +{ + GParamSpec *spec = g_object_class_find_property (g_type_class_ref (gtype), name); + g_value_init (value, spec->value_type); +} + GType gtksharp_value_get_value_type (GValue *value) { diff --git a/gtk/Dialog.custom b/gtk/Dialog.custom index a3f93893e..ce4b42048 100644 --- a/gtk/Dialog.custom +++ b/gtk/Dialog.custom @@ -14,8 +14,22 @@ static extern IntPtr gtk_dialog_new_with_buttons (string title, IntPtr i, int flags, IntPtr dummy); public Dialog (string title, Gtk.Window parent, Gtk.DialogFlags flags) : base(IntPtr.Zero) { - if (GetType() != typeof (Dialog)) - throw new InvalidOperationException ("Can't chain to this constructor from subclasses."); + if (GetType() != typeof (Dialog)) { + GLib.Value[] vals = new GLib.Value [1]; + string[] names = new string [1]; + names [0] = "title"; + vals [0] = new GLib.Value (title); + CreateNativeObject (names, vals); + TransientFor = parent; + if ((flags & DialogFlags.Modal) > 0) + Modal = true; + if ((flags & DialogFlags.DestroyWithParent) > 0) + DestroyWithParent = true; + if ((flags & DialogFlags.NoSeparator) > 0) + HasSeparator = false; + return; + } + Raw = gtk_dialog_new_with_buttons (title, parent.Handle, (int) flags, IntPtr.Zero); } diff --git a/gtk/Gtk.metadata b/gtk/Gtk.metadata index d79ab05e3..ea3a47eae 100644 --- a/gtk/Gtk.metadata +++ b/gtk/Gtk.metadata @@ -67,6 +67,7 @@ PackEnd PackStart 1 + label Click Press Release @@ -116,6 +117,7 @@ Selected Toggled 1 + label 1 1 1 diff --git a/sample/Subclass.cs b/sample/Subclass.cs index f4b3d3b02..433787e7a 100755 --- a/sample/Subclass.cs +++ b/sample/Subclass.cs @@ -31,20 +31,7 @@ namespace GtkSamples { public class MyButton : Gtk.Button { - static GLib.GType gtype = GLib.GType.Invalid; - - public MyButton () : base (GType) - { - Label = "I'm a subclassed button"; - } - - public static new GLib.GType GType { - get { - if (gtype == GLib.GType.Invalid) - gtype = RegisterGType (typeof (MyButton)); - return gtype; - } - } + public MyButton () : base ("I'm a subclassed button") {} protected override void OnClicked () {