65
70
// finalized->release->dispose->re-wrap resurrection cycle.
66
71
// We use a dynamic method to access internal/private GTK# API in a performant way without having to track
67
72
// per-instance delegates.
68
public static void FixContainerLeak<T> (T c)
71
if (fixedContainerTypes.Add (t)) {
72
if (forallCallback == null) {
73
forallCallback = CreateForallCallback ();
73
public static void FixContainerLeak (Gtk.Container c)
75
if (containerLeakFixed) {
78
FixContainerLeak (c.GetType ());
81
static void FixContainerLeak (Type t)
83
if (containerLeakFixed) {
87
if (fixedContainerTypes == null) {
89
gtksharp_container_leak_fixed_marker ();
90
containerLeakFixed = true;
92
} catch (EntryPointNotFoundException) {
75
var gt = (GLib.GType) t.GetMethod ("LookupGType", BindingFlags.Instance | BindingFlags.NonPublic).Invoke (c, null);
76
gtksharp_container_override_forall (gt.Val, forallCallback);
94
fixedContainerTypes = new HashSet<Type>();
95
forallCallbacks = new Dictionary<IntPtr, ForallDelegate> ();
98
if (!fixedContainerTypes.Add (t)) {
102
//need to fix the callback for the type and all the managed supertypes
103
var lookupGType = typeof (GLib.Object).GetMethod ("LookupGType", BindingFlags.Static | BindingFlags.NonPublic);
105
var gt = (GLib.GType) lookupGType.Invoke (null, new[] { t });
106
var cb = CreateForallCallback (gt.Val);
107
forallCallbacks[gt.Val] = cb;
108
gtksharp_container_override_forall (gt.Val, cb);
110
} while (fixedContainerTypes.Add (t) && t.Assembly != typeof (Gtk.Container).Assembly);
80
static ForallDelegate CreateForallCallback ()
113
static ForallDelegate CreateForallCallback (IntPtr gtype)
82
115
var dm = new DynamicMethod (
83
116
"ContainerForallCallback",
85
new Type[] { typeof (IntPtr), typeof (bool), typeof (IntPtr), typeof (IntPtr) },
86
typeof (GtkWorkarounds).Module,
118
new Type[] { typeof(IntPtr), typeof(bool), typeof(IntPtr), typeof(IntPtr) },
119
typeof(GtkWorkarounds).Module,
89
var invokerType = typeof (Gtk.Container.CallbackInvoker);
122
var invokerType = typeof(Gtk.Container.CallbackInvoker);
91
124
//this was based on compiling a similar method and disassembling it
92
125
ILGenerator il = dm.GetILGenerator ();
93
126
var IL_002b = il.DefineLabel ();
94
127
var IL_003f = il.DefineLabel ();
95
128
var IL_0060 = il.DefineLabel ();
96
var IL_0072 = il.DefineLabel ();
98
var loc_container = il.DeclareLocal (typeof (Gtk.Container));
99
var loc_obj = il.DeclareLocal (typeof (object));
129
var label_return = il.DefineLabel ();
131
var loc_container = il.DeclareLocal (typeof(Gtk.Container));
132
var loc_obj = il.DeclareLocal (typeof(object));
100
133
var loc_invoker = il.DeclareLocal (invokerType);
101
var loc_ex = il.DeclareLocal (typeof (Exception));
134
var loc_ex = il.DeclareLocal (typeof(Exception));
136
//check that the type is an exact match
137
// prevent stack overflow, because the callback on a more derived type will handle everything
138
il.Emit (OpCodes.Ldarg_0);
139
il.Emit (OpCodes.Call, typeof(GLib.ObjectManager).GetMethod ("gtksharp_get_type_id", BindingFlags.Static | BindingFlags.NonPublic));
141
il.Emit (OpCodes.Ldc_I8, gtype.ToInt64 ());
142
il.Emit (OpCodes.Newobj, typeof (IntPtr).GetConstructor (new Type[] { typeof (Int64) }));
143
il.Emit (OpCodes.Call, typeof (IntPtr).GetMethod ("op_Equality", BindingFlags.Static | BindingFlags.Public));
144
il.Emit (OpCodes.Brfalse, label_return);
103
146
il.BeginExceptionBlock ();
104
147
il.Emit (OpCodes.Ldnull);
105
148
il.Emit (OpCodes.Stloc, loc_container);
153
196
il.Emit (OpCodes.Ldloc, loc_ex);
154
197
il.Emit (OpCodes.Ldc_I4_0);
155
198
il.Emit (OpCodes.Call, typeof (GLib.ExceptionManager).GetMethod ("RaiseUnhandledException"));
156
il.Emit (OpCodes.Leave, IL_0072);
199
il.Emit (OpCodes.Leave, label_return);
157
200
il.EndExceptionBlock ();
159
il.MarkLabel (IL_0072);
202
il.MarkLabel (label_return);
160
203
il.Emit (OpCodes.Ret);
162
205
return (ForallDelegate) dm.CreateDelegate (typeof (ForallDelegate));
208
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
166
209
delegate void ForallDelegate (IntPtr container, bool include_internals, IntPtr cb, IntPtr data);
168
[DllImport("gtksharpglue-2")]
211
[DllImport("gtksharpglue-2", CallingConvention = CallingConvention.Cdecl)]
169
212
static extern void gtksharp_container_override_forall (IntPtr gtype, ForallDelegate cb);