Skip to content
This repository has been archived by the owner on Oct 1, 2024. It is now read-only.

Generate static callbacks #208

Merged
merged 24 commits into from
Dec 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6438490
[Gen] Generate with static callback where applicable.
Therzok Jun 17, 2017
6ce8e67
[Gdk] Fix extra space which didn't match type.
Therzok Jun 17, 2017
3a642df
[Gen] Fix generator not validating imported data
Therzok Jun 17, 2017
f55855f
[Gtk] Get rid of some hacks and properly implement quit/input add
Therzok Jun 17, 2017
7bdc338
[Gtk] Modify custom TextBuffer delegate wrapper.
Therzok Jun 18, 2017
42f63e4
[Gen] Set some callback gen members on validation
Therzok Dec 9, 2017
ee63d91
[Gen] Improve codegen of callbacks.
Therzok Dec 9, 2017
8c54918
[Gen] Avoid generating invoker if not used.
Therzok Dec 9, 2017
b9c5953
[Gen] Handle all user data cases
Therzok Dec 9, 2017
b8d274b
[Gen] Avoid allocating wrapper class if not needed.
Therzok Dec 9, 2017
7fa0084
[Gen] Some more static generation in async handlers
Therzok Dec 9, 2017
ae7dcdf
[Gen] Fix callback marshal return so static can be used
Therzok Dec 9, 2017
ab2d1e4
[Gen] Marshal Gdk.FilterFunc as static wrapper
Therzok Dec 9, 2017
7605b6c
[Clipboard] Make some callbacks static.
Therzok Dec 10, 2017
dc98831
[Gen] Fix handlers to return a managed delegate for a native one
Therzok Dec 11, 2017
9fd1bf1
[Gen] Manually gen callback returning pinvokes.
Therzok Dec 12, 2017
4832c29
[Gen] Use WeakReference instead of IntPtr to track delegates
Therzok Dec 12, 2017
b2f8dbb
Add missing files
Therzok Dec 12, 2017
f0be1c5
Remove useless metadata
Therzok Dec 12, 2017
a77ebbe
Add comment explaining intentional leak
Therzok Dec 12, 2017
7c7a632
Set callback_wrapper
Therzok Dec 12, 2017
bf83193
[About] use the right pinvoke
Therzok Dec 12, 2017
9c38c8b
[TreeModelFilter] Don't gchandle.Alloc(null)
Therzok Dec 12, 2017
627d644
Review feedback
Therzok Dec 13, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions gdk/Display.custom
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,9 @@

public void AddClientMessageFilter (Gdk.Atom message_type, Gdk.FilterFunc func)
{
GdkSharp.FilterFuncWrapper func_wrapper = new GdkSharp.FilterFuncWrapper (func);
if (!PersistentData.Contains ("client_message_filter_func_list"))
PersistentData ["client_message_filter_func_list"] = new ArrayList ();
ArrayList func_list = PersistentData ["client_message_filter_func_list"] as ArrayList;
func_list.Add (func_wrapper);
gdk_display_add_client_message_filter (Handle, message_type == null ? IntPtr.Zero : message_type.Handle, func_wrapper.NativeDelegate, IntPtr.Zero);
// Purposefully leak this indefinitely, there's no gdk_display_remove_client_message_filter.
var gch = GCHandle.Alloc (func);
gdk_display_add_client_message_filter (Handle, message_type == null ? IntPtr.Zero : message_type.Handle, GdkSharp.FilterFuncWrapper.NativeDelegate, (IntPtr)gch);
}

[DllImport("libgdk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
Expand Down
2 changes: 1 addition & 1 deletion gdk/Gdk.metadata
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@
<attr path="/api/namespace/struct[@cname='GdkTimeCoord']/field[@cname='axes']" name="array_len">128</attr>
<attr path="/api/namespace/struct[@cname='GdkWindowObject']" name="hidden">1</attr>
<attr path="/api/namespace/struct[@cname='GdkPixbufFormat']/method[@cname='gdk_pixbuf_format_get_extensions']/return-type" name="owned">true</attr>
<attr path="/api/namespace/struct[@cname='GdkPixbufFormat']/method[@cname='gdk_pixbuf_format_get_mime_types ']/return-type" name="owned">true</attr>
<attr path="/api/namespace/struct[@cname='GdkPixbufFormat']/method[@cname='gdk_pixbuf_format_get_mime_types']/return-type" name="owned">true</attr>
<attr path="/api/namespace/class[@cname='GdkChar_']/method[@cname='gdk_char_height']/parameters/parameter[@name='character']" name="type">guchar</attr>
<attr path="/api/namespace/class[@cname='GdkChar_']/method[@cname='gdk_char_width']/parameters/parameter[@name='character']" name="type">guchar</attr>
<attr path="/api/namespace/class[@cname='GdkChar_']/method[@cname='gdk_char_measure']/parameters/parameter[@name='character']" name="type">guchar</attr>
Expand Down
10 changes: 4 additions & 6 deletions gdk/Input.custom
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,13 @@
[Obsolete]
public static int AddFull (int source, Gdk.InputCondition condition, Gdk.InputFunction function, IntPtr data, Gdk.DestroyNotify destroy)
{
GdkSharp.InputFunctionWrapper function_wrapper = new GdkSharp.InputFunctionWrapper (function);
GCHandle gch = GCHandle.Alloc (function_wrapper);
return gdk_input_add_full (source, (int) condition, function_wrapper.NativeDelegate, (IntPtr) gch, GLib.DestroyHelper.NotifyHandler);
GCHandle gch = GCHandle.Alloc (function);
return gdk_input_add_full (source, (int) condition, GdkSharp.InputFunctionWrapper.NativeDelegate, (IntPtr) gch, GLib.DestroyHelper.NotifyHandler);
}

[Obsolete]
public static int Add (int source, Gdk.InputCondition condition, Gdk.InputFunction function)
{
GdkSharp.InputFunctionWrapper function_wrapper = new GdkSharp.InputFunctionWrapper (function);
GCHandle gch = GCHandle.Alloc (function_wrapper);
return gdk_input_add_full (source, (int) condition, function_wrapper.NativeDelegate, (IntPtr) gch, GLib.DestroyHelper.NotifyHandler);
GCHandle gch = GCHandle.Alloc (function);
return gdk_input_add_full (source, (int) condition, GdkSharp.InputFunctionWrapper.NativeDelegate, (IntPtr) gch, GLib.DestroyHelper.NotifyHandler);
}
5 changes: 3 additions & 2 deletions gdk/Pixbuf.custom
Original file line number Diff line number Diff line change
Expand Up @@ -379,12 +379,13 @@

public unsafe void SaveToCallback (PixbufSaveFunc save_func, string type, string[] option_keys, string[] option_values)
{
GdkSharp.PixbufSaveFuncWrapper save_func_wrapper = new GdkSharp.PixbufSaveFuncWrapper (save_func);
GCHandle gch = GCHandle.Alloc (save_func);
IntPtr error = IntPtr.Zero;
IntPtr ntype = GLib.Marshaller.StringToPtrGStrdup (type);
IntPtr[] nkeys = NullTerm (option_keys);
IntPtr[] nvals = NullTerm (option_values);
bool saved = gdk_pixbuf_save_to_callbackv (Handle, save_func_wrapper.NativeDelegate, IntPtr.Zero, ntype, nkeys, nvals, out error);
bool saved = gdk_pixbuf_save_to_callbackv (Handle, GdkSharp.PixbufSaveFuncWrapper.NativeDelegate, (IntPtr)gch, ntype, nkeys, nvals, out error);
gch.Free ();
GLib.Marshaller.Free (ntype);
ReleaseArray (nkeys);
ReleaseArray (nvals);
Expand Down
28 changes: 16 additions & 12 deletions gdk/Window.custom
Original file line number Diff line number Diff line change
Expand Up @@ -120,38 +120,42 @@

public static void AddFilterForAll (FilterFunc func)
{
GdkSharp.FilterFuncWrapper wrapper = new GdkSharp.FilterFuncWrapper (func);
FilterAllHash [func] = wrapper;
gdk_window_add_filter (IntPtr.Zero, wrapper.NativeDelegate, IntPtr.Zero);
var gch = GCHandle.Alloc (func);
FilterAllHash [func] = gch;
gdk_window_add_filter (IntPtr.Zero, GdkSharp.FilterFuncWrapper.NativeDelegate, (IntPtr)gch);
}

public static void RemoveFilterForAll (FilterFunc func)
{
GdkSharp.FilterFuncWrapper wrapper = FilterAllHash [func] as GdkSharp.FilterFuncWrapper;
if (wrapper == null)
var ret = FilterAllHash [func];
if (ret == null)
return;
GCHandle gch = (GCHandle)ret;
FilterAllHash.Remove (func);
gdk_window_remove_filter (IntPtr.Zero, wrapper.NativeDelegate, IntPtr.Zero);
gdk_window_remove_filter (IntPtr.Zero, GdkSharp.FilterFuncWrapper.NativeDelegate, (IntPtr)gch);
gch.Free();
}

public void AddFilter (FilterFunc function)
{
if (!PersistentData.Contains ("filter_func_hash"))
PersistentData ["filter_func_hash"] = new Hashtable ();
Hashtable hash = PersistentData ["filter_func_hash"] as Hashtable;
GdkSharp.FilterFuncWrapper wrapper = new GdkSharp.FilterFuncWrapper (function);
hash [function] = wrapper;
gdk_window_add_filter (Handle, wrapper.NativeDelegate, IntPtr.Zero);
var gch = GCHandle.Alloc (function);
hash [function] = gch;
gdk_window_add_filter (Handle, GdkSharp.FilterFuncWrapper.NativeDelegate, (IntPtr)gch);
}

public void RemoveFilter (FilterFunc function)
{
Hashtable hash = PersistentData ["filter_func_hash"] as Hashtable;
GdkSharp.FilterFuncWrapper wrapper = hash [function] as GdkSharp.FilterFuncWrapper;
if (wrapper == null)
var ret = hash [function];
if (ret == null)
return;
GCHandle gch = (GCHandle)ret;
hash.Remove (function);
gdk_window_remove_filter (Handle, wrapper.NativeDelegate, IntPtr.Zero);
gdk_window_remove_filter (Handle, GdkSharp.FilterFuncWrapper.NativeDelegate, (IntPtr)gch);
gch.Free();
}

#if MANLY_ENOUGH_TO_INCLUDE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤣

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, noticed it too

Expand Down
149 changes: 114 additions & 35 deletions generator/CallbackGen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
namespace GtkSharp.Generation {

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;

public class CallbackGen : GenBase, IAccessor {
Expand All @@ -32,12 +34,15 @@ public class CallbackGen : GenBase, IAccessor {
private Signature sig = null;
private ReturnValue retval;
private bool valid = true;
internal List<string> parameterScopeList = new List<string> ();
internal bool hasInvoker = false;

public CallbackGen (XmlElement ns, XmlElement elem) : base (ns, elem)
{
retval = new ReturnValue (elem ["return-type"]);
parms = new Parameters (elem ["parameters"]);
parms.HideData = true;
hasInvoker = elem.HasAttribute ("has_invoker");
}

public override string DefaultValue {
Expand All @@ -60,6 +65,9 @@ public override bool Validate ()
return false;
}

if (!ManagedCallString.Validate (parms))
return false;

valid = true;
return true;
}
Expand All @@ -83,18 +91,20 @@ public override string MarshalType {

public override string CallByName (string var_name)
{
if (WithParamGCHandle)
return NS + "Sharp." + Name + "Wrapper.NativeDelegate";
return var_name + ".NativeDelegate";
}

public override string FromNative (string var)
{
return NS + "Sharp." + Name + "Wrapper.GetManagedDelegate (" + var + ")";
return "new " + NS + "Sharp." + Name + "Invoker (" + var + ").Handler";
}

public void WriteAccessors (StreamWriter sw, string indent, string var)
{
sw.WriteLine (indent + "get {");
sw.WriteLine (indent + "\treturn " + FromNative (var) + ";");
sw.WriteLine (indent + "\treturn new GtkSharp." + Name + "Invoker (" + var + ").Handler;");
sw.WriteLine (indent + "}");
}

Expand Down Expand Up @@ -133,6 +143,9 @@ string InvokeString {

void GenInvoker (GenerationInfo gen_info, StreamWriter sw)
{
if (!hasInvoker)
return;

if (sig == null)
sig = new Signature (parms);

Expand Down Expand Up @@ -186,6 +199,44 @@ void GenInvoker (GenerationInfo gen_info, StreamWriter sw)
sw.WriteLine ();
}

Parameter gcHandleParam;
bool? withParamGCHandle;
public bool WithParamGCHandle {
get {
if (withParamGCHandle == null) {
withParamGCHandle = false;
for (int i = 0; i < parms.Count; ++i) {
if (parms [i].IsUserData) {
withParamGCHandle = true;
gcHandleParam = parms [i];
break;
}
}
if (Elem.HasAttribute ("force_instance"))
withParamGCHandle = false;
}
return withParamGCHandle.Value;
}
}

public bool HasOnlyAsyncCall {
get {
return parameterScopeList.All (x => x == "async");
}
}

bool HasAsyncCall {
get {
return parameterScopeList.Any (x => x == "async");
}
}

public bool GenerateStaticWrapper {
get {
return WithParamGCHandle && (!HasAsyncCall || HasOnlyAsyncCall);
}
}

public string GenWrapper (GenerationInfo gen_info)
{
string wrapper = Name + "Native";
Expand All @@ -209,26 +260,46 @@ public string GenWrapper (GenerationInfo gen_info)
sw.WriteLine ("\tinternal delegate " + retval.MarshalType + " " + wrapper + "(" + parms.CallbackImportSignature + ");");
sw.WriteLine ();
GenInvoker (gen_info, sw);
sw.WriteLine ("\tinternal class " + Name + "Wrapper {");
sw.WriteLine ("\tinternal {0}class {1}Wrapper {{", GenerateStaticWrapper ? "static " : "", Name);
sw.WriteLine ();
ManagedCallString call = new ManagedCallString (parms, false);
sw.WriteLine ("\t\tpublic " + retval.MarshalType + " NativeCallback (" + parms.CallbackImportSignature + ")");

sw.WriteLine ("\t\tpublic " + (WithParamGCHandle ? "static " : "") + retval.MarshalType + " NativeCallback (" + parms.CallbackImportSignature + ")");
sw.WriteLine ("\t\t{");

ManagedCallString call = new ManagedCallString (parms, false);
string unconditional = call.Unconditional ("\t\t\t");
if (unconditional.Length > 0)
sw.WriteLine (unconditional);
sw.WriteLine ("\t\t\ttry {");
string call_setup = call.Setup ("\t\t\t\t");
if (call_setup.Length > 0)
sw.WriteLine (call_setup);

if (WithParamGCHandle) {
sw.WriteLine ("\t\t\t\tvar gch = (GCHandle){0};", gcHandleParam.Name);
if (GenerateStaticWrapper)
sw.WriteLine ("\t\t\t\tvar managed = ({0})gch.Target;", QualifiedName);
else
sw.WriteLine ("\t\t\t\tvar wrapper = ({0}Wrapper)gch.Target;", Name);
}

string callPrefix = string.Empty;
if (WithParamGCHandle && !GenerateStaticWrapper)
callPrefix = "wrapper.";

if (retval.CSType == "void")
sw.WriteLine ("\t\t\t\tmanaged ({0});", call);
sw.WriteLine ("\t\t\t\t{0}managed ({1});", callPrefix, call);
else
sw.WriteLine ("\t\t\t\t{0} __ret = managed ({1});", retval.CSType, call);
sw.WriteLine ("\t\t\t\t{0} __ret = {1}managed ({2});", retval.CSType, callPrefix, call);
string finish = call.Finish ("\t\t\t\t");
if (finish.Length > 0)
sw.WriteLine (finish);
sw.WriteLine ("\t\t\t\tif (release_on_call)\n\t\t\t\t\tgch.Free ();");
if (HasAsyncCall) {
if (!HasOnlyAsyncCall)
sw.WriteLine ("\t\t\t\tif ({0}release_on_call)\n\t\t\t\t\tgch.Free ();", callPrefix);
else
sw.WriteLine ("\t\t\t\t\tgch.Free ();");
}
if (retval.CSType != "void")
sw.WriteLine ("\t\t\t\treturn {0};", retval.ToNative ("__ret"));

Expand All @@ -247,34 +318,42 @@ public string GenWrapper (GenerationInfo gen_info)
sw.WriteLine ("\t\t\t}");
sw.WriteLine ("\t\t}");
sw.WriteLine ();
sw.WriteLine ("\t\tbool release_on_call = false;");
sw.WriteLine ("\t\tGCHandle gch;");
sw.WriteLine ();
sw.WriteLine ("\t\tpublic void PersistUntilCalled ()");
sw.WriteLine ("\t\t{");
sw.WriteLine ("\t\t\trelease_on_call = true;");
sw.WriteLine ("\t\t\tgch = GCHandle.Alloc (this);");
sw.WriteLine ("\t\t}");
sw.WriteLine ();
sw.WriteLine ("\t\tinternal " + wrapper + " NativeDelegate;");
sw.WriteLine ("\t\t" + NS + "." + Name + " managed;");
sw.WriteLine ();
sw.WriteLine ("\t\tpublic " + Name + "Wrapper (" + NS + "." + Name + " managed)");
sw.WriteLine ("\t\t{");
sw.WriteLine ("\t\t\tthis.managed = managed;");
sw.WriteLine ("\t\t\tif (managed != null)");
sw.WriteLine ("\t\t\t\tNativeDelegate = new " + wrapper + " (NativeCallback);");
sw.WriteLine ("\t\t}");
if (!GenerateStaticWrapper && HasAsyncCall) {
sw.WriteLine ("\t\tbool release_on_call = false;");
if (!WithParamGCHandle)
sw.WriteLine ("\t\tGCHandle gch;");
sw.WriteLine ();
if (WithParamGCHandle)
sw.WriteLine ("\t\tpublic GCHandle PersistUntilCalled ()");
else
sw.WriteLine ("\t\tpublic void PersistUntilCalled ()");
sw.WriteLine ("\t\t{");
sw.WriteLine ("\t\t\trelease_on_call = true;");
if (WithParamGCHandle)
sw.WriteLine ("\t\t\treturn GCHandle.Alloc (this);");
else
sw.WriteLine ("\t\t\tgch = GCHandle.Alloc (this);");
sw.WriteLine ("\t\t}");
}
sw.WriteLine ();
sw.WriteLine ("\t\tpublic static " + NS + "." + Name + " GetManagedDelegate (" + wrapper + " native)");
sw.WriteLine ("\t\t{");
sw.WriteLine ("\t\t\tif (native == null)");
sw.WriteLine ("\t\t\t\treturn null;");
sw.WriteLine ("\t\t\t" + Name + "Wrapper wrapper = (" + Name + "Wrapper) native.Target;");
sw.WriteLine ("\t\t\tif (wrapper == null)");
sw.WriteLine ("\t\t\t\treturn null;");
sw.WriteLine ("\t\t\treturn wrapper.managed;");
sw.WriteLine ("\t\t}");
sw.Write ("\t\tinternal " + (WithParamGCHandle ? "static " : "") + "readonly " + wrapper + " NativeDelegate");
if (WithParamGCHandle)
sw.WriteLine (" = new " + wrapper + " (NativeCallback);");
else
sw.WriteLine (";");
if (!GenerateStaticWrapper) {
sw.WriteLine ("\t\t" + NS + "." + Name + " managed;");
sw.WriteLine ();
sw.WriteLine ("\t\tpublic " + Name + "Wrapper (" + NS + "." + Name + " managed)");
sw.WriteLine ("\t\t{");
sw.WriteLine ("\t\t\tthis.managed = managed;");
if (!WithParamGCHandle) {
sw.WriteLine ("\t\t\tif (managed != null)");
sw.WriteLine ("\t\t\t\tNativeDelegate = new " + wrapper + " (NativeCallback);");
}
sw.WriteLine ("\t\t}");
sw.WriteLine ();
}
sw.WriteLine ("\t}");
sw.WriteLine ("#endregion");
sw.WriteLine ("}");
Expand Down
6 changes: 5 additions & 1 deletion generator/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ public static int Main (string[] args)

Parser p = new Parser ();
IGeneratable[] curr_gens = p.Parse (filename);
table.AddTypes (curr_gens);
table.AddTypes (curr_gens);
if (!generate) {
foreach (var gen in curr_gens)
gen.Validate ();
}
if (generate)
gens.AddRange (curr_gens);
}
Expand Down
2 changes: 1 addition & 1 deletion generator/FieldBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace GtkSharp.Generation {
public abstract class FieldBase : PropertyBase {
public FieldBase (XmlElement elem, ClassBase container_type) : base (elem, container_type) {}

public bool Validate ()
public virtual bool Validate ()
{
if (!Ignored && !Hidden && CSType == "") {
Console.Write("Field {0} has unknown Type {1} ", Name, CType);
Expand Down
11 changes: 11 additions & 0 deletions generator/ManagedCallString.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ public ManagedCallString (Parameters parms, bool drop_first)
}
}

public static bool Validate (Parameters parms)
{
for (int i = 0; i < parms.Count; i++) {
var gen = parms [i].Generatable as CallbackGen;
if (gen != null)
gen.hasInvoker = true;
}

return true;
}

public bool HasOutParam {
get {
foreach (Parameter p in parms) {
Expand Down
Loading