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:
parent
b9d94385a6
commit
39ac15b6b6
4 changed files with 168 additions and 41 deletions
17
ChangeLog
17
ChangeLog
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue