2008-05-02 Mike Kestner <mkestner@novell.com>

* generator/GenerationInfo.cs:  refactor glue writer implementation
	so that GlueEnabled means there is a valid glue writer available.
	Avoids crashes in scenarios where an unwriteable glue path is provided
	to the generator.  Generate a glue function which scans the type
	hierarchy of an object for the most-derived unmanaged ancestor so
	that we can invoke class methods on it, avoiding infinite recursions.
	* generator/Signal.cs: revamp the default handler vm overriding 
	mechanism.  When class fields exist which can be directly hooked into,
	we now generate glue to override and chain up to unmanaged base funcs.
	This avoids some strangeness in the g_signal_override_class_closure
	and g_signal_chain_from_overridden reported in #332300 and also lays
	the groundwork for automated generation of non-signal VMs.
	* gtk/Gtk.metadata: block signal glue generation for a few types which 
	don't seem to install headers.

svn path=/trunk/gtk-sharp/; revision=102350
This commit is contained in:
Mike Kestner 2008-05-02 17:10:05 +00:00
parent b9d94385a6
commit 39ac15b6b6
4 changed files with 168 additions and 41 deletions

View File

@ -1,3 +1,20 @@
2008-05-02 Mike Kestner <mkestner@novell.com>
* generator/GenerationInfo.cs: refactor glue writer implementation
so that GlueEnabled means there is a valid glue writer available.
Avoids crashes in scenarios where an unwriteable glue path is provided
to the generator. Generate a glue function which scans the type
hierarchy of an object for the most-derived unmanaged ancestor so
that we can invoke class methods on it, avoiding infinite recursions.
* generator/Signal.cs: revamp the default handler vm overriding
mechanism. When class fields exist which can be directly hooked into,
we now generate glue to override and chain up to unmanaged base funcs.
This avoids some strangeness in the g_signal_override_class_closure
and g_signal_chain_from_overridden reported in #332300 and also lays
the groundwork for automated generation of non-signal VMs.
* gtk/Gtk.metadata: block signal glue generation for a few types which
don't seem to install headers.
2008-05-02 Mike Kestner <mkestner@novell.com>
* glib/Object.cs: Don't bother hooking VM into the class field

View File

@ -2,7 +2,7 @@
//
// Author: Mike Kestner <mkestner@ximian.com>
//
// Copyright (c) 2003-2005 Novell Inc.
// Copyright (c) 2003-2008 Novell Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
@ -31,10 +31,10 @@ namespace GtkSharp.Generation {
string dir;
string custom_dir;
string assembly_name;
string glue_filename;
string glue_includes;
string gluelib_name;
bool glue_enabled;
StreamWriter sw;
StreamWriter glue_sw;
public GenerationInfo (XmlElement ns)
{
@ -43,9 +43,6 @@ namespace GtkSharp.Generation {
dir = ".." + sep + ns_name.ToLower () + sep + "generated";
custom_dir = ".." + sep + ns_name.ToLower ();
assembly_name = ns_name.ToLower () + "-sharp";
gluelib_name = "";
glue_filename = "";
glue_includes = "";
}
public GenerationInfo (string dir, string assembly_name) : this (dir, dir, assembly_name, "", "", "") {}
@ -55,9 +52,48 @@ namespace GtkSharp.Generation {
this.dir = dir;
this.custom_dir = custom_dir;
this.assembly_name = assembly_name;
this.glue_filename = glue_filename;
this.glue_includes = glue_includes;
this.gluelib_name = gluelib_name;
InitializeGlue (glue_filename, glue_includes, gluelib_name);
}
void InitializeGlue (string glue_filename, string glue_includes, string gluelib_name)
{
if (gluelib_name != String.Empty && glue_filename != String.Empty) {
FileStream stream;
try {
stream = new FileStream (glue_filename, FileMode.Create, FileAccess.Write);
} catch (Exception) {
Console.Error.WriteLine ("Unable to create specified glue file. Glue will not be generated.");
return;
}
glue_sw = new StreamWriter (stream);
glue_sw.WriteLine ("// This file was generated by the Gtk# code generator.");
glue_sw.WriteLine ("// Any changes made will be lost if regenerated.");
glue_sw.WriteLine ();
if (glue_includes != "") {
foreach (string header in glue_includes.Split (new char[] {',', ' '})) {
if (header != "")
glue_sw.WriteLine ("#include <{0}>", header);
}
glue_sw.WriteLine ("");
}
glue_sw.WriteLine ("const gchar *__prefix = \"__gtksharp_\";\n");
glue_sw.WriteLine ("#define HAS_PREFIX(a) (*((guint64 *)(a)) == *((guint64 *) __prefix))\n");
glue_sw.WriteLine ("static GObjectClass *");
glue_sw.WriteLine ("get_threshold_class (GObject *obj)");
glue_sw.WriteLine ("{");
glue_sw.WriteLine ("\tGType gtype = G_TYPE_FROM_INSTANCE (obj);");
glue_sw.WriteLine ("\twhile (HAS_PREFIX (g_type_name (gtype)))");
glue_sw.WriteLine ("\t\tgtype = g_type_parent (gtype);");
glue_sw.WriteLine ("\tGObjectClass *klass = g_type_class_peek (gtype);");
glue_sw.WriteLine ("\tif (klass == NULL) klass = g_type_class_ref (gtype);");
glue_sw.WriteLine ("\treturn klass;");
glue_sw.WriteLine ("}\n");
glue_enabled = true;
}
}
public string AssemblyName {
@ -86,39 +122,12 @@ namespace GtkSharp.Generation {
public bool GlueEnabled {
get {
return gluelib_name != String.Empty && glue_filename != String.Empty;
return glue_enabled;
}
}
public string GlueFilename {
get {
return glue_filename;
}
}
StreamWriter glue_sw = null;
public StreamWriter GlueWriter {
get {
if (!GlueEnabled)
return null;
if (glue_sw == null) {
FileStream stream = new FileStream (glue_filename, FileMode.Create, FileAccess.Write);
glue_sw = new StreamWriter (stream);
glue_sw.WriteLine ("// This file was generated by the Gtk# code generator.");
glue_sw.WriteLine ("// Any changes made will be lost if regenerated.");
glue_sw.WriteLine ();
if (glue_includes != "") {
foreach (string header in glue_includes.Split (new char[] {',', ' '})) {
if (header != "")
glue_sw.WriteLine ("#include <{0}>", header);
}
glue_sw.WriteLine ("");
}
}
return glue_sw;
}
}

View File

@ -219,7 +219,7 @@ namespace GtkSharp.Generation {
sw.Close ();
}
private void GenVirtualMethod (StreamWriter sw, ClassBase implementor)
private void GenVMDeclaration (StreamWriter sw, ClassBase implementor)
{
VMSignature vmsig = new VMSignature (parms);
sw.WriteLine ("\t\t[GLib.DefaultSignalHandler(Type=typeof(" + (implementor != null ? implementor.QualifiedName : container_type.QualifiedName) + "), ConnectionMethod=\"Override" + Name +"\")]");
@ -227,6 +227,101 @@ namespace GtkSharp.Generation {
if (NeedNew (implementor))
sw.Write ("new ");
sw.WriteLine ("virtual {0} {1} ({2})", retval.CSType, "On" + Name, vmsig.ToString ());
}
private string CastFromInt (string type)
{
return type != "int" ? "(" + type + ") " : "";
}
private string GlueCallString {
get {
string result = "Handle";
for (int i = 1; i < parms.Count; i++) {
Parameter p = parms [i];
IGeneratable igen = p.Generatable;
if (i > 1 && parms [i - 1].IsString && p.IsLength && p.PassAs == String.Empty) {
string string_name = parms [i - 1].Name;
result += ", " + igen.CallByName (CastFromInt (p.CSType) + "System.Text.Encoding.UTF8.GetByteCount (" + string_name + ")");
continue;
}
p.CallName = p.Name;
string call_parm = p.CallString;
if (p.IsUserData && parms.IsHidden (p) && !parms.HideData && (i == 1 || parms [i - 1].Scope != "notified")) {
call_parm = "IntPtr.Zero";
}
result += ", " + call_parm;
}
return result;
}
}
private string GlueSignature {
get {
string result = String.Empty;
for (int i = 0; i < parms.Count; i++)
result += parms[i].CType.Replace ("const-", "const ") + " " + parms[i].Name + (i == parms.Count-1 ? "" : ", ");
return result;
}
}
private string DefaultGlueValue {
get {
string val = retval.DefaultValue;
switch (val) {
case "null":
return "NULL";
case "false":
return "FALSE";
case "true":
return "TRUE";
default:
return val;
}
}
}
private void GenGlueVirtualMethod (GenerationInfo gen_info)
{
StreamWriter glue = gen_info.GlueWriter;
string glue_name = String.Format ("{0}sharp_{1}_base_{2}", container_type.NS.ToLower ().Replace (".", "_"), container_type.Name.ToLower (), ClassFieldName);
glue.WriteLine ("{0} {1} ({2});\n", retval.CType, glue_name, GlueSignature);
glue.WriteLine ("{0}\n{1} ({2})", retval.CType, glue_name, GlueSignature);
glue.WriteLine ("{");
glue.WriteLine ("\t{0}Class *klass = ({0}Class *) get_threshold_class (G_OBJECT ({1}));", container_type.CName, parms[0].Name);
glue.Write ("\tif (klass->{0})\n\t\t", ClassFieldName);
if (!IsVoid)
glue.Write ("return ");
glue.Write ("(* klass->{0}) (", ClassFieldName);
for (int i = 0; i < parms.Count; i++)
glue.Write (parms[i].Name + (i == parms.Count - 1 ? "" : ", "));
glue.WriteLine (");");
if (!IsVoid)
glue.WriteLine ("\treturn " + DefaultGlueValue + ";");
glue.WriteLine ("}");
StreamWriter sw = gen_info.Writer;
sw.WriteLine ("\t\t[DllImport (\"{0}\")]", gen_info.GluelibName);
sw.WriteLine ("\t\tstatic extern {0} {1} ({2});\n", retval.MarshalType, glue_name, parms.ImportSignature);
GenVMDeclaration (sw, null);
sw.WriteLine ("\t\t{");
MethodBody body = new MethodBody (parms);
body.Initialize (gen_info, false, false, String.Empty);
sw.WriteLine ("\t\t\t{0}{1} ({2});", IsVoid ? "" : retval.MarshalType + " __ret = ", glue_name, GlueCallString);
body.Finish (sw, "");
if (!IsVoid)
sw.WriteLine ("\t\t\treturn {0};", retval.FromNative ("__ret"));
sw.WriteLine ("\t\t}\n");
}
private void GenChainVirtualMethod (StreamWriter sw, ClassBase implementor)
{
GenVMDeclaration (sw, implementor);
sw.WriteLine ("\t\t{");
if (IsVoid)
sw.WriteLine ("\t\t\tGLib.Value ret = GLib.Value.Empty;");
@ -283,8 +378,7 @@ namespace GtkSharp.Generation {
{
StreamWriter sw = gen_info.Writer;
StreamWriter glue;
bool use_glue = false;
//bool use_glue = glue != null && implementor == null && ClassFieldName.Length > 0;
bool use_glue = gen_info.GlueEnabled && implementor == null && ClassFieldName.Length > 0;
string glue_name = String.Empty;
ManagedCallString call = new ManagedCallString (parms);
sw.WriteLine ("\t\t[GLib.CDeclCallback]");
@ -292,7 +386,7 @@ namespace GtkSharp.Generation {
if (use_glue) {
glue = gen_info.GlueWriter;
glue_name = String.Format ("{0}sharp_{1}_{2}", container_type.NS.ToLower ().Replace (".", "_"), container_type.Name.ToLower (), ClassFieldName);
glue_name = String.Format ("{0}sharp_{1}_override_{2}", container_type.NS.ToLower ().Replace (".", "_"), container_type.Name.ToLower (), ClassFieldName);
sw.WriteLine ("\t\t[DllImport (\"{0}\")]", gen_info.GluelibName);
sw.WriteLine ("\t\tstatic extern void {0} (IntPtr gtype, {1}VMDelegate cb);\n", glue_name, Name);
glue.WriteLine ("void {0} (GType gtype, gpointer cb);\n", glue_name);
@ -365,7 +459,10 @@ namespace GtkSharp.Generation {
GenEventHandler (gen_info);
GenDefaultHandlerDelegate (gen_info, implementor);
GenVirtualMethod (sw, implementor);
if (gen_info.GlueEnabled && implementor == null && ClassFieldName.Length > 0)
GenGlueVirtualMethod (gen_info);
else
GenChainVirtualMethod (sw, implementor);
GenEvent (sw, implementor, "this");
Statistics.SignalCount++;

View File

@ -281,6 +281,7 @@
<attr path="/api/namespace/object[@cname='GtkClipboard']/method[@name='WaitForContents']/return-type" name="owned">true</attr>
<attr path="/api/namespace/object[@cname='GtkClipboard']/method[@name='WaitForRichText']" name="hidden">1</attr>
<attr path="/api/namespace/object[@cname='GtkClipboard']/method[@name='RequestRichText']" name="hidden">1</attr>
<attr path="/api/namespace/object[@cname='GtkClipboard']/signal" name="field_name"></attr>
<attr path="/api/namespace/object[@cname='GtkColorButton']/method[@name='GetColor']/*/*[@name='color']" name="pass_as">out</attr>
<attr path="/api/namespace/object[@cname='GtkColorSelection']/method[@name='GetColor']" name="hidden">1</attr>
<attr path="/api/namespace/object[@cname='GtkColorSelection']/method[@name='GetCurrentColor']/*/*[@name='color']" name="pass_as">out</attr>
@ -379,6 +380,7 @@
<attr path="/api/namespace/object[@cname='GtkFrame']/method[@name='SetLabelAlign']" name="hidden">1</attr>
<attr path="/api/namespace/object[@cname='GtkHandleBox']/property[@name='ShadowType']" name="hidden">1</attr>
<attr path="/api/namespace/object[@cname='GtkHScale']/constructor[@cname='gtk_hscale_new_with_range']" name="hidden">1</attr>
<attr path="/api/namespace/object[@cname='GtkHSV']/signal" name="field_name"></attr>
<attr path="/api/namespace/object[@cname='GtkIconTheme']/method[@name='ChooseIcon']/*/*[@name='icon_names']" name="null_term_array">1</attr>
<attr path="/api/namespace/object[@cname='GtkIconTheme']/method[@name='GetIconSizes']" name="hidden">1</attr>
<attr path="/api/namespace/object[@cname='GtkIconTheme']/method[@name='GetSearchPath']" name="hidden">1</attr>
@ -502,8 +504,10 @@
<attr path="/api/namespace/object[@cname='GtkPrinter']/method[@name='ListPapers']/return-type" name="element_type">GtkPageSetup*</attr>
<attr path="/api/namespace/object[@cname='GtkPrinter']/method[@name='ListPapers']/return-type" name="owned">true</attr>
<attr path="/api/namespace/object[@cname='GtkPrinter']/method[@name='ListPapers']/return-type" name="elements_owned">true</attr>
<attr path="/api/namespace/object[@cname='GtkPrinter']/signal" name="field_name"></attr>
<attr path="/api/namespace/object[@cname='GtkPrinterOptionSet']/method[@name='Foreach']/*/*[@name='func']" name="scope">call</attr>
<attr path="/api/namespace/object[@cname='GtkPrinterOptionSet']/method[@name='ForeachInGroup']/*/*[@name='func']" name="scope">call</attr>
<attr path="/api/namespace/object[@cname='GtkPrintJob']/signal" name="field_name"></attr>
<attr path="/api/namespace/object[@cname='GtkPrintSettings']/constructor[@cname='gtk_print_settings_new_from_file']/*/*[@name='file_name']" name="type">const-gfilename*</attr>
<attr path="/api/namespace/object[@cname='GtkPrintSettings']/method[@name='Foreach']/*/*[@name='func']" name="scope">call</attr>
<attr path="/api/namespace/object[@cname='GtkPrintSettings']/method[@name='ToFile']/*/*[@name='file_name']" name="type">const-gfilename*</attr>