~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to src/addins/MonoDevelop.GtkCore/libstetic/editor/GtkWorkarounds.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
56
56
                        return false;
57
57
                }
58
58
                
59
 
                static HashSet<Type> fixedContainerTypes = new HashSet<Type>();
60
 
                static ForallDelegate forallCallback;
 
59
 
 
60
                [DllImport ("gtksharpglue-2", CallingConvention = CallingConvention.Cdecl)]
 
61
                static extern void gtksharp_container_leak_fixed_marker ();
 
62
 
 
63
                static HashSet<Type> fixedContainerTypes;
 
64
                static Dictionary<IntPtr,ForallDelegate> forallCallbacks;
 
65
                static bool containerLeakFixed;
61
66
                
62
67
                // Works around BXC #3801 - Managed Container subclasses are incorrectly resurrected, then leak.
63
68
                // It does this by registering an alternative callback for gtksharp_container_override_forall, which
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)
69
 
                {
70
 
                        var t = typeof (T);
71
 
                        if (fixedContainerTypes.Add (t)) {
72
 
                                if (forallCallback == null) {
73
 
                                        forallCallback = CreateForallCallback ();
 
73
                public static void FixContainerLeak (Gtk.Container c)
 
74
                {
 
75
                        if (containerLeakFixed) {
 
76
                                return;
 
77
                        }
 
78
                        FixContainerLeak (c.GetType ());
 
79
                }
 
80
 
 
81
                static void FixContainerLeak (Type t)
 
82
                {
 
83
                        if (containerLeakFixed) {
 
84
                                return;
 
85
                        }
 
86
 
 
87
                        if (fixedContainerTypes == null) {
 
88
                                try {
 
89
                                        gtksharp_container_leak_fixed_marker ();
 
90
                                        containerLeakFixed = true;
 
91
                                        return;
 
92
                                } catch (EntryPointNotFoundException) {
74
93
                                }
75
 
                                var gt = (GLib.GType) t.GetMethod ("LookupGType", BindingFlags.Instance | BindingFlags.NonPublic).Invoke (c, null);
76
 
                                gtksharp_container_override_forall (gt.Val, forallCallback);
77
 
                        }
 
94
                                fixedContainerTypes = new HashSet<Type>();
 
95
                                forallCallbacks = new Dictionary<IntPtr, ForallDelegate> ();
 
96
                        }
 
97
 
 
98
                        if (!fixedContainerTypes.Add (t)) {
 
99
                                return;
 
100
                        }
 
101
 
 
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);
 
104
                        do {
 
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);
 
109
                                t = t.BaseType;
 
110
                        } while (fixedContainerTypes.Add (t) && t.Assembly != typeof (Gtk.Container).Assembly);
78
111
                }
79
 
                
80
 
                static ForallDelegate CreateForallCallback ()
 
112
 
 
113
                static ForallDelegate CreateForallCallback (IntPtr gtype)
81
114
                {
82
115
                        var dm = new DynamicMethod (
83
116
                                "ContainerForallCallback",
84
 
                                typeof (void),
85
 
                                new Type[] { typeof (IntPtr), typeof (bool), typeof (IntPtr), typeof (IntPtr) },
86
 
                                typeof (GtkWorkarounds).Module,
 
117
                                typeof(void),
 
118
                                new Type[] { typeof(IntPtr), typeof(bool), typeof(IntPtr), typeof(IntPtr) },
 
119
                                typeof(GtkWorkarounds).Module,
87
120
                                true);
88
121
                        
89
 
                        var invokerType = typeof (Gtk.Container.CallbackInvoker);
 
122
                        var invokerType = typeof(Gtk.Container.CallbackInvoker);
90
123
                        
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 ();
97
 
                        
98
 
                        var loc_container  = il.DeclareLocal (typeof (Gtk.Container));
99
 
                        var loc_obj = il.DeclareLocal (typeof (object));
 
129
                        var label_return = il.DefineLabel ();
 
130
 
 
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));
102
 
                        
 
134
                        var loc_ex = il.DeclareLocal (typeof(Exception));
 
135
 
 
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));
 
140
 
 
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);
 
145
 
103
146
                        il.BeginExceptionBlock ();
104
147
                        il.Emit (OpCodes.Ldnull);
105
148
                        il.Emit (OpCodes.Stloc, loc_container);
110
153
                        il.Emit (OpCodes.Stloc, loc_obj);
111
154
                        il.Emit (OpCodes.Ldloc, loc_obj);
112
155
                        il.Emit (OpCodes.Brfalse, IL_002b);
113
 
                        
 
156
 
114
157
                        var tref = typeof (GLib.Object).Assembly.GetType ("GLib.ToggleRef");
115
158
                        il.Emit (OpCodes.Ldloc, loc_obj);
116
159
                        il.Emit (OpCodes.Castclass, tref);
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 ();
158
201
                        
159
 
                        il.MarkLabel (IL_0072);
 
202
                        il.MarkLabel (label_return);
160
203
                        il.Emit (OpCodes.Ret);
161
204
                        
162
205
                        return (ForallDelegate) dm.CreateDelegate (typeof (ForallDelegate));
163
206
                }
164
207
                
165
 
                [GLib.CDeclCallback]
 
208
                [UnmanagedFunctionPointer (CallingConvention.Cdecl)]
166
209
                delegate void ForallDelegate (IntPtr container, bool include_internals, IntPtr cb, IntPtr data);
167
210
                
168
 
                [DllImport("gtksharpglue-2")]
 
211
                [DllImport("gtksharpglue-2", CallingConvention = CallingConvention.Cdecl)]
169
212
                static extern void gtksharp_container_override_forall (IntPtr gtype, ForallDelegate cb);
170
213
        }
171
214