summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
authorVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-04-05 19:59:34 -0300
committerVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-04-05 19:59:47 -0300
commit7c28762f15f9935d5ca08ef87ee7ddfaf1df4815 (patch)
tree3b602d7fb867e91c202f262b7aaa215c8245856b /src/bin
parent1c22a3d8190fd85570418a076356547f3eda606f (diff)
efl-csharp: fix crash when events trigger after C# object `Dispose`
Summary: Rework general event handling to check individually each event call, if the object is not alive then the event will not be propagated. WeakReferences (and lambdas capturing those WeakRefs) are used to ensure this. Dispose methods in object now take care of checking if efl libraries are still initialized and thread-safely unregister each event before performing an efl_unref on the Eo object. Event handling in C# is now centered around a single dictionary inside the object: `EoEvents`. C# event triggers now properly trigger events on C too. Standardize C# event-triggering methods names (remove underscores). Some diminished use of static memory due events no longer requiring static key objects to be registered/unregistered. Some fixing of white space generation for generated events. Depends on D8431 Reviewers: lauromoura, felipealmeida, segfaultxavi Reviewed By: lauromoura Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D8564
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/eolian_mono/eolian/mono/events.hh280
-rw-r--r--src/bin/eolian_mono/eolian/mono/klass.hh215
-rw-r--r--src/bin/eolian_mono/eolian_mono.cc1
3 files changed, 271 insertions, 225 deletions
diff --git a/src/bin/eolian_mono/eolian/mono/events.hh b/src/bin/eolian_mono/eolian/mono/events.hh
index ea042fb08e..56a22d7823 100644
--- a/src/bin/eolian_mono/eolian/mono/events.hh
+++ b/src/bin/eolian_mono/eolian/mono/events.hh
@@ -30,7 +30,7 @@ struct unpack_event_args_visitor
30 // Structs are usually passed by pointer to events, like having a ptr<> modifier 30 // Structs are usually passed by pointer to events, like having a ptr<> modifier
31 // Uses implicit conversion from IntPtr 31 // Uses implicit conversion from IntPtr
32 return as_generator( 32 return as_generator(
33 " evt.Info;" 33 " evt.Info"
34 ).generate(sink, attributes::unused, *context); 34 ).generate(sink, attributes::unused, *context);
35 } 35 }
36 else if (type.is_ptr) 36 else if (type.is_ptr)
@@ -81,6 +81,116 @@ struct unpack_event_args_visitor
81 } 81 }
82}; 82};
83 83
84template<typename OutputIterator, typename Context>
85struct pack_event_info_and_call_visitor
86{
87 mutable OutputIterator sink;
88 Context const* context;
89 attributes::type_def const& type;
90
91 static auto constexpr native_call = "Efl.Eo.Globals.efl_event_callback_call(this.NativeHandle, desc, info);\n";
92
93 typedef pack_event_info_and_call_visitor<OutputIterator, Context> visitor_type;
94 typedef bool result_type;
95
96 bool operator()(grammar::attributes::regular_type_def const& regular) const
97 {
98 std::string arg_type = name_helpers::type_full_managed_name(regular);
99
100 auto const& indent = current_indentation(*context);
101
102 if (regular.is_struct())
103 {
104 return as_generator(
105 indent << "IntPtr info = Marshal.AllocHGlobal(Marshal.SizeOf(e.arg));\n"
106 << indent << "try\n"
107 << indent << "{\n"
108 << indent << scope_tab << "Marshal.StructureToPtr(e.arg, info, false);\n"
109 << indent << scope_tab << this->native_call
110 << indent << "}\n"
111 << indent << "finally\n"
112 << indent << "{\n"
113 << indent << scope_tab << "Marshal.FreeHGlobal(info);\n"
114 << indent << "}\n"
115 ).generate(sink, attributes::unused, *context);
116 }
117
118 using attributes::regular_type_def;
119 struct match
120 {
121 eina::optional<std::string> name;
122 std::function<std::string()> function;
123 };
124
125 std::string full_type_name = name_helpers::type_full_eolian_name(regular);
126 auto filter_func = [&regular, &full_type_name] (match const& m)
127 {
128 return (!m.name || *m.name == regular.base_type || *m.name == full_type_name);
129 };
130
131 match const str_table[] =
132 {
133 {"string", [] { return "e.arg"; }}
134 , {"stringshare", [] { return "e.arg"; }}
135 };
136
137 auto str_accept_func = [&](std::string const& conversion)
138 {
139 return as_generator(
140 indent << "IntPtr info = Eina.StringConversion.ManagedStringToNativeUtf8Alloc(" << conversion << ");\n"
141 << indent << "try\n"
142 << indent << "{\n"
143 << indent << scope_tab << this->native_call
144 << indent << "}\n"
145 << indent << "finally\n"
146 << indent << "{\n"
147 << indent << scope_tab << "Eina.MemoryNative.Free(info);\n"
148 << indent << "}\n").generate(sink, attributes::unused, *context);
149 };
150
151 if (eina::optional<bool> b = call_match(str_table, filter_func, str_accept_func))
152 return *b;
153
154 match const value_table [] =
155 {
156 {"bool", [] { return "e.arg ? (byte) 1 : (byte) 0"; }}
157 , {"Eina.Error", [] { return "(int)e.arg"; }}
158 , {nullptr, [] { return "e.arg"; }}
159 };
160
161 auto value_accept_func = [&](std::string const& conversion)
162 {
163 return as_generator(
164 indent << "IntPtr info = Eina.PrimitiveConversion.ManagedToPointerAlloc(" << conversion << ");\n"
165 << indent << "try\n"
166 << indent << "{\n"
167 << indent << scope_tab << this->native_call
168 << indent << "}\n"
169 << indent << "finally\n"
170 << indent << "{\n"
171 << indent << scope_tab << "Marshal.FreeHGlobal(info);\n"
172 << indent << "}\n").generate(sink, attributes::unused, *context);
173 };
174
175 if (eina::optional<bool> b = call_match(value_table, filter_func, value_accept_func))
176 return *b;
177
178 return value_accept_func("e.args");
179 }
180 bool operator()(grammar::attributes::klass_name const&) const
181 {
182 auto const& indent = current_indentation(*context);
183 return as_generator(indent << "IntPtr info = e.arg.NativeHandle;\n"
184 << indent << this->native_call).generate(sink, attributes::unused, *context);
185 }
186 bool operator()(attributes::complex_type_def const&) const
187 {
188 auto const& indent = current_indentation(*context);
189 return as_generator(indent << "IntPtr info = e.arg.Handle;\n"
190 << indent << this->native_call).generate(sink, attributes::unused, *context);
191 }
192};
193
84/* 194/*
85 * Generates a struct wrapping the argument of a given event. 195 * Generates a struct wrapping the argument of a given event.
86 */ 196 */
@@ -138,40 +248,6 @@ struct event_declaration_generator
138 } 248 }
139} const event_declaration {}; 249} const event_declaration {};
140 250
141struct event_registration_generator
142{
143 attributes::klass_def const& klass;
144 attributes::klass_def const& leaf_klass;
145 bool is_inherited_event;
146
147 template<typename OutputIterator, typename Context>
148 bool generate(OutputIterator sink, attributes::event_def const& evt, Context const& context) const
149 {
150 std::string wrapper_event_name;
151
152 if (blacklist::is_event_blacklisted(evt, context))
153 return true;
154
155 if (is_inherited_event && !helpers::is_unique_event(evt, leaf_klass))
156 wrapper_event_name = name_helpers::translate_inherited_event_name(evt, klass);
157 else
158 wrapper_event_name = name_helpers::managed_event_name(evt.name);
159
160 return as_generator(scope_tab << scope_tab << "evt_" << wrapper_event_name << "_delegate = "
161 << "new Efl.EventCb(on_" << wrapper_event_name << "_NativeCallback);\n"
162 ).generate(sink, attributes::unused, context);
163 }
164};
165
166struct event_registration_parameterized
167{
168 event_registration_generator operator()(attributes::klass_def const& klass, attributes::klass_def const& leaf_klass) const
169 {
170 bool is_inherited_event = klass != leaf_klass;
171 return {klass, leaf_klass, is_inherited_event};
172 }
173} const event_registration;
174
175struct event_definition_generator 251struct event_definition_generator
176{ 252{
177 attributes::klass_def const& klass; 253 attributes::klass_def const& klass;
@@ -185,6 +261,7 @@ struct event_definition_generator
185 return true; 261 return true;
186 262
187 std::string managed_evt_name = name_helpers::managed_event_name(evt.name); 263 std::string managed_evt_name = name_helpers::managed_event_name(evt.name);
264 auto const& indent = current_indentation(context);
188 265
189 bool is_unique = helpers::is_unique_event(evt, leaf_klass); 266 bool is_unique = helpers::is_unique_event(evt, leaf_klass);
190 bool use_explicit_impl = is_inherited_event && !is_unique; 267 bool use_explicit_impl = is_inherited_event && !is_unique;
@@ -205,20 +282,35 @@ struct event_definition_generator
205 std::string wrapper_args_type = "EventArgs"; 282 std::string wrapper_args_type = "EventArgs";
206 std::string wrapper_args_template = ""; 283 std::string wrapper_args_template = "";
207 std::string event_args = "EventArgs args = EventArgs.Empty;\n"; 284 std::string event_args = "EventArgs args = EventArgs.Empty;\n";
285 std::string event_native_call;
208 286
209 efl::eina::optional<grammar::attributes::type_def> etype = evt.type; 287 efl::eina::optional<grammar::attributes::type_def> etype = evt.type;
210 288
211 if (etype.is_engaged()) 289 if (!etype.is_engaged())
290 {
291 auto event_call_site_sink = std::back_inserter(event_native_call);
292 if (!as_generator(indent.inc().inc() << "Efl.Eo.Globals.efl_event_callback_call(this.NativeHandle, desc, IntPtr.Zero);\n")
293 .generate(event_call_site_sink, attributes::unused, context))
294 return false;
295 }
296 else
212 { 297 {
213 wrapper_args_type = name_helpers::managed_event_args_name(evt); 298 wrapper_args_type = name_helpers::managed_event_args_name(evt);
214 wrapper_args_template = "<" + wrapper_args_type + ">"; 299 wrapper_args_template = "<" + wrapper_args_type + ">";
215 std::string arg_initializer = wrapper_args_type + " args = new " + wrapper_args_type + "();\n"; 300 std::string arg_initializer;
216
217 arg_initializer += " args.arg = ";
218 301
219 auto arg_initializer_sink = std::back_inserter(arg_initializer); 302 auto arg_initializer_sink = std::back_inserter(arg_initializer);
303 auto event_call_site_sink = std::back_inserter(event_native_call);
304
305 auto sub_context = change_indentation(indent.inc().inc(), context);
220 306
221 if (!(*etype).original_type.visit(unpack_event_args_visitor<decltype(arg_initializer_sink), Context>{arg_initializer_sink, &context, *etype})) 307 if (!as_generator(scope_tab(6) << wrapper_args_type << " args = new " << wrapper_args_type << "();\n"
308 << scope_tab(6) << "args.arg = ").generate(arg_initializer_sink, attributes::unused, context))
309 return false;
310 if (!(*etype).original_type.visit(unpack_event_args_visitor<decltype(arg_initializer_sink), decltype(sub_context)>{arg_initializer_sink, &sub_context, *etype}))
311 return false;
312
313 if (!(*etype).original_type.visit(pack_event_info_and_call_visitor<decltype(event_call_site_sink), decltype(sub_context)>{event_call_site_sink, &sub_context, *etype}))
222 return false; 314 return false;
223 315
224 arg_initializer += ";\n"; 316 arg_initializer += ";\n";
@@ -226,10 +318,6 @@ struct event_definition_generator
226 event_args = arg_initializer; 318 event_args = arg_initializer;
227 } 319 }
228 320
229 if(!as_generator("private static object " << wrapper_evt_name << "Key = new object();\n")
230 .generate(sink, attributes::unused, context))
231 return false;
232
233 if(!as_generator(documentation(1)).generate(sink, evt, context)) 321 if(!as_generator(documentation(1)).generate(sink, evt, context))
234 return false; 322 return false;
235 323
@@ -256,31 +344,10 @@ struct event_definition_generator
256 return false; 344 return false;
257 } 345 }
258 346
259 if (!generate_event_add_remove(sink, evt, wrapper_evt_name, context)) 347 if (!generate_event_add_remove(sink, evt, event_args, context))
260 return false;
261
262 if (!generate_event_trigger(sink, wrapper_evt_name, wrapper_args_type, wrapper_args_template, context))
263 return false; 348 return false;
264 349
265 // Store the delegate for this event in this instance. This is initialized in RegisterEventProxies() 350 if (!generate_event_trigger(sink, evt, wrapper_evt_name, wrapper_args_type, event_native_call, context))
266 // We can't initialize them directly here as they depend on the member methods being valid (i.e.
267 // the constructor being called).
268 if (!as_generator(scope_tab << "Efl.EventCb evt_" << wrapper_evt_name << "_delegate;\n").generate(sink, attributes::unused, context))
269 return false;
270
271 // Callback to be given to C's callback_priority_add
272 if (!as_generator(
273 scope_tab << "private void on_" << wrapper_evt_name << "_NativeCallback(System.IntPtr data, ref Efl.Event.NativeStruct evt)\n"
274 << scope_tab << "{\n"
275 << scope_tab << scope_tab << event_args
276 << scope_tab << scope_tab << "try {\n"
277 << scope_tab << scope_tab << scope_tab << "On_" << wrapper_evt_name << "(args);\n"
278 << scope_tab << scope_tab << "} catch (Exception e) {\n"
279 << scope_tab << scope_tab << scope_tab << "Eina.Log.Error(e.ToString());\n"
280 << scope_tab << scope_tab << scope_tab << "Eina.Error.Set(Eina.Error.UNHANDLED_EXCEPTION);\n"
281 << scope_tab << scope_tab << "}\n"
282 << scope_tab << "}\n\n"
283 ).generate(sink, attributes::unused, context))
284 return false; 351 return false;
285 352
286 return true; 353 return true;
@@ -288,21 +355,26 @@ struct event_definition_generator
288 355
289 template<typename OutputIterator, typename Context> 356 template<typename OutputIterator, typename Context>
290 bool generate_event_trigger(OutputIterator sink 357 bool generate_event_trigger(OutputIterator sink
358 , attributes::event_def const &evt
291 , std::string const& event_name 359 , std::string const& event_name
292 , std::string const& event_args_type 360 , std::string const& event_args_type
293 , std::string const& event_template_args 361 , std::string const& event_native_call
294 , Context const& context) const 362 , Context const& context) const
295 { 363 {
296 auto delegate_type = "EventHandler" + event_template_args; 364 auto library_name = context_find_tag<library_context>(context).actual_library_name(klass.filename);
365 std::string upper_c_name = utils::to_uppercase(evt.c_name);
297 if (!as_generator( 366 if (!as_generator(
298 scope_tab << "///<summary>Method to raise event "<< event_name << ".</summary>\n" 367 scope_tab << "///<summary>Method to raise event "<< event_name << ".</summary>\n"
299 << scope_tab << "public void On_" << event_name << "(" << event_args_type << " e)\n" 368 << scope_tab << "public void On" << event_name << "(" << event_args_type << " e)\n"
300 << scope_tab << "{\n" 369 << scope_tab << "{\n"
301 << scope_tab << scope_tab << delegate_type << " evt;\n" 370 << scope_tab << scope_tab << "var key = \"_" << upper_c_name << "\";\n"
302 << scope_tab << scope_tab << "lock (eventLock) {\n" 371 << scope_tab << scope_tab << "IntPtr desc = Efl.EventDescription.GetNative(" << library_name << ", key);\n"
303 << scope_tab << scope_tab << "evt = (" << delegate_type << ")eventHandlers[" << event_name << "Key];\n" 372 << scope_tab << scope_tab << "if (desc == IntPtr.Zero)\n"
304 << scope_tab << scope_tab << "}\n" 373 << scope_tab << scope_tab << "{\n"
305 << scope_tab << scope_tab << "evt?.Invoke(this, e);\n" 374 << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to get native event {key}\");\n"
375 << scope_tab << scope_tab << scope_tab << "return;\n"
376 << scope_tab << scope_tab << "}\n\n"
377 << event_native_call
306 << scope_tab << "}\n" 378 << scope_tab << "}\n"
307 ).generate(sink, nullptr, context)) 379 ).generate(sink, nullptr, context))
308 return false; 380 return false;
@@ -311,7 +383,10 @@ struct event_definition_generator
311 } 383 }
312 384
313 template<typename OutputIterator, typename Context> 385 template<typename OutputIterator, typename Context>
314 bool generate_event_add_remove(OutputIterator sink, attributes::event_def const &evt, const std::string& event_name, Context const& context) const 386 bool generate_event_add_remove(OutputIterator sink
387 , attributes::event_def const &evt
388 , std::string const& event_args
389 , Context const& context) const
315 { 390 {
316 std::string upper_c_name = utils::to_uppercase(evt.c_name); 391 std::string upper_c_name = utils::to_uppercase(evt.c_name);
317 auto unit = (const Eolian_Unit*) context_find_tag<eolian_state_context>(context).state; 392 auto unit = (const Eolian_Unit*) context_find_tag<eolian_state_context>(context).state;
@@ -319,22 +394,38 @@ struct event_definition_generator
319 auto library_name = context_find_tag<library_context>(context).actual_library_name(klass.filename); 394 auto library_name = context_find_tag<library_context>(context).actual_library_name(klass.filename);
320 return as_generator( 395 return as_generator(
321 scope_tab << "{\n" 396 scope_tab << "{\n"
322 << scope_tab << scope_tab << "add {\n" 397 << scope_tab << scope_tab << "add\n"
323 << scope_tab << scope_tab << scope_tab << "lock (eventLock) {\n" 398 << scope_tab << scope_tab << "{\n"
399 << scope_tab << scope_tab << scope_tab << "lock (eventLock)\n"
400 << scope_tab << scope_tab << scope_tab << "{\n"
401 << scope_tab << scope_tab << scope_tab << scope_tab << "var wRef = new WeakReference(this);\n"
402 << scope_tab << scope_tab << scope_tab << scope_tab << "Efl.EventCb callerCb = (IntPtr data, ref Efl.Event.NativeStruct evt) =>\n"
403 << scope_tab << scope_tab << scope_tab << scope_tab << "{\n"
404 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "var obj = wRef.Target as Efl.Eo.IWrapper;\n"
405 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "if (obj != null)\n"
406 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "{\n"
407 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << event_args
408 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "try\n"
409 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "{\n"
410 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "value?.Invoke(obj, args);\n"
411 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "}\n"
412 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "catch (Exception e)\n"
413 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "{\n"
414 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error(e.ToString());\n"
415 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Error.Set(Eina.Error.UNHANDLED_EXCEPTION);\n"
416 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "}\n"
417 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "}\n"
418 << scope_tab << scope_tab << scope_tab << scope_tab << "};\n\n"
324 << scope_tab << scope_tab << scope_tab << scope_tab << "string key = \"_" << upper_c_name << "\";\n" 419 << scope_tab << scope_tab << scope_tab << scope_tab << "string key = \"_" << upper_c_name << "\";\n"
325 << scope_tab << scope_tab << scope_tab << scope_tab << "if (AddNativeEventHandler(" << library_name << ", key, this.evt_" << event_name << "_delegate)) {\n" 420 << scope_tab << scope_tab << scope_tab << scope_tab << "AddNativeEventHandler(" << library_name << ", key, callerCb, value);\n"
326 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "eventHandlers.AddHandler(" << event_name << "Key , value);\n"
327 << scope_tab << scope_tab << scope_tab << scope_tab << "} else\n"
328 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Error adding proxy for event {key}\");\n"
329 << scope_tab << scope_tab << scope_tab << "}\n" // End of lock block 421 << scope_tab << scope_tab << scope_tab << "}\n" // End of lock block
330 << scope_tab << scope_tab << "}\n" 422 << scope_tab << scope_tab << "}\n\n"
331 << scope_tab << scope_tab << "remove {\n" 423 << scope_tab << scope_tab << "remove\n"
332 << scope_tab << scope_tab << scope_tab << "lock (eventLock) {\n" 424 << scope_tab << scope_tab << "{\n"
425 << scope_tab << scope_tab << scope_tab << "lock (eventLock)\n"
426 << scope_tab << scope_tab << scope_tab << "{\n"
333 << scope_tab << scope_tab << scope_tab << scope_tab << "string key = \"_" << upper_c_name << "\";\n" 427 << scope_tab << scope_tab << scope_tab << scope_tab << "string key = \"_" << upper_c_name << "\";\n"
334 << scope_tab << scope_tab << scope_tab << scope_tab << "if (RemoveNativeEventHandler(key, this.evt_" << event_name << "_delegate)) { \n" 428 << scope_tab << scope_tab << scope_tab << scope_tab << "RemoveNativeEventHandler(" << library_name << ", key, value);\n"
335 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "eventHandlers.RemoveHandler(" << event_name << "Key , value);\n"
336 << scope_tab << scope_tab << scope_tab << scope_tab << "} else\n"
337 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Error removing proxy for event {key}\");\n"
338 << scope_tab << scope_tab << scope_tab << "}\n" // End of lock block 429 << scope_tab << scope_tab << scope_tab << "}\n" // End of lock block
339 << scope_tab << scope_tab << "}\n" 430 << scope_tab << scope_tab << "}\n"
340 << scope_tab << "}\n" 431 << scope_tab << "}\n"
@@ -366,13 +457,6 @@ template <>
366struct is_generator<struct ::eolian_mono::event_declaration_generator> : std::true_type {}; 457struct is_generator<struct ::eolian_mono::event_declaration_generator> : std::true_type {};
367 458
368template <> 459template <>
369struct is_eager_generator<struct ::eolian_mono::event_registration_generator> : std::true_type {};
370template <>
371struct is_generator<struct ::eolian_mono::event_registration_generator> : std::true_type {};
372template <>
373struct is_generator<struct ::eolian_mono::event_registration_parameterized> : std::true_type {};
374
375template <>
376struct is_eager_generator<struct ::eolian_mono::event_definition_generator> : std::true_type {}; 460struct is_eager_generator<struct ::eolian_mono::event_definition_generator> : std::true_type {};
377template <> 461template <>
378struct is_generator<struct ::eolian_mono::event_definition_generator> : std::true_type {}; 462struct is_generator<struct ::eolian_mono::event_definition_generator> : std::true_type {};
@@ -385,10 +469,6 @@ struct attributes_needed<struct ::eolian_mono::event_argument_wrapper_generator>
385template <> 469template <>
386struct attributes_needed<struct ::eolian_mono::event_declaration_generator> : std::integral_constant<int, 1> {}; 470struct attributes_needed<struct ::eolian_mono::event_declaration_generator> : std::integral_constant<int, 1> {};
387template <> 471template <>
388struct attributes_needed<struct ::eolian_mono::event_registration_generator> : std::integral_constant<int, 1> {};
389template <>
390struct attributes_needed<struct ::eolian_mono::event_registration_parameterized> : std::integral_constant<int, 1> {};
391template <>
392struct attributes_needed<struct ::eolian_mono::event_definition_generator> : std::integral_constant<int, 1> {}; 472struct attributes_needed<struct ::eolian_mono::event_definition_generator> : std::integral_constant<int, 1> {};
393template <> 473template <>
394struct attributes_needed<struct ::eolian_mono::event_definition_parameterized> : std::integral_constant<int, 1> {}; 474struct attributes_needed<struct ::eolian_mono::event_definition_parameterized> : std::integral_constant<int, 1> {};
diff --git a/src/bin/eolian_mono/eolian/mono/klass.hh b/src/bin/eolian_mono/eolian/mono/klass.hh
index 7973c7d763..e34a126321 100644
--- a/src/bin/eolian_mono/eolian/mono/klass.hh
+++ b/src/bin/eolian_mono/eolian/mono/klass.hh
@@ -223,7 +223,6 @@ struct klass
223 << scope_tab << "private " << concrete_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n" 223 << scope_tab << "private " << concrete_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
224 << scope_tab << "{\n" 224 << scope_tab << "{\n"
225 << scope_tab << scope_tab << (root ? "handle = raw;\n" : "") 225 << scope_tab << scope_tab << (root ? "handle = raw;\n" : "")
226 << scope_tab << scope_tab << "RegisterEventProxies();\n"
227 << scope_tab << "}\n" 226 << scope_tab << "}\n"
228 ) 227 )
229 .generate(sink, attributes::unused, concrete_cxt)) 228 .generate(sink, attributes::unused, concrete_cxt))
@@ -238,9 +237,6 @@ struct klass
238 if (!generate_events(sink, cls, concrete_cxt)) 237 if (!generate_events(sink, cls, concrete_cxt))
239 return false; 238 return false;
240 239
241 if (!generate_events_registration(sink, cls, concrete_cxt))
242 return false;
243
244 // Parts 240 // Parts
245 if(!as_generator(*(part_definition)) 241 if(!as_generator(*(part_definition))
246 .generate(sink, cls.parts, concrete_cxt)) return false; 242 .generate(sink, cls.parts, concrete_cxt)) return false;
@@ -316,9 +312,6 @@ struct klass
316 if (!generate_events(sink, cls, inherit_cxt)) 312 if (!generate_events(sink, cls, inherit_cxt))
317 return false; 313 return false;
318 314
319 if (!generate_events_registration(sink, cls, inherit_cxt))
320 return false;
321
322 // Parts 315 // Parts
323 if(!as_generator(*(part_definition)) 316 if(!as_generator(*(part_definition))
324 .generate(sink, cls.parts, inherit_cxt)) return false; 317 .generate(sink, cls.parts, inherit_cxt)) return false;
@@ -459,7 +452,9 @@ struct klass
459 return true; 452 return true;
460 453
461 if (cls.get_all_events().size() > 0) 454 if (cls.get_all_events().size() > 0)
462 if (!as_generator(scope_tab << (is_inherit ? "protected " : "private ") << "EventHandlerList eventHandlers = new EventHandlerList();\n").generate(sink, attributes::unused, context)) 455 if (!as_generator(scope_tab << visibility << "Dictionary<(IntPtr desc, object evtDelegate), (IntPtr evtCallerPtr, Efl.EventCb evtCaller)> eoEvents = new Dictionary<(IntPtr desc, object evtDelegate), (IntPtr evtCallerPtr, Efl.EventCb evtCaller)>();\n"
456 << scope_tab << visibility << "readonly object eventLock = new object();\n")
457 .generate(sink, attributes::unused, context))
463 return false; 458 return false;
464 459
465 if (is_inherit) 460 if (is_inherit)
@@ -517,7 +512,6 @@ struct klass
517 << scope_tab << "protected " << inherit_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n" 512 << scope_tab << "protected " << inherit_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
518 << scope_tab << "{\n" 513 << scope_tab << "{\n"
519 << scope_tab << scope_tab << (root ? "handle = raw;\n" : "") 514 << scope_tab << scope_tab << (root ? "handle = raw;\n" : "")
520 << scope_tab << scope_tab << "RegisterEventProxies();\n"
521 << scope_tab << "}\n" 515 << scope_tab << "}\n"
522 ).generate(sink, std::make_tuple(constructors, constructors, constructors), context)) 516 ).generate(sink, std::make_tuple(constructors, constructors, constructors), context))
523 return false; 517 return false;
@@ -560,7 +554,6 @@ struct klass
560 << scope_tab << scope_tab << scope_tab << "actual_klass = Efl.Eo.ClassRegister.GetInheritKlassOrRegister(base_klass, ((object)this).GetType());\n" 554 << scope_tab << scope_tab << scope_tab << "actual_klass = Efl.Eo.ClassRegister.GetInheritKlassOrRegister(base_klass, ((object)this).GetType());\n"
561 << scope_tab << scope_tab << "}\n" 555 << scope_tab << scope_tab << "}\n"
562 << scope_tab << scope_tab << "handle = Efl.Eo.Globals.instantiate_start(actual_klass, parent);\n" 556 << scope_tab << scope_tab << "handle = Efl.Eo.Globals.instantiate_start(actual_klass, parent);\n"
563 << scope_tab << scope_tab << "RegisterEventProxies();\n"
564 << scope_tab << scope_tab << "if (inherited)\n" 557 << scope_tab << scope_tab << "if (inherited)\n"
565 << scope_tab << scope_tab << "{\n" 558 << scope_tab << scope_tab << "{\n"
566 << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.PrivateDataSet(this);\n" 559 << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.PrivateDataSet(this);\n"
@@ -580,7 +573,6 @@ struct klass
580 template <typename OutputIterator, typename Context> 573 template <typename OutputIterator, typename Context>
581 bool generate_dispose_methods(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const 574 bool generate_dispose_methods(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const
582 { 575 {
583 std::string name = join_namespaces(cls.namespaces, '.') + cls.eolian_name;
584 if (helpers::has_regular_ancestor(cls)) 576 if (helpers::has_regular_ancestor(cls))
585 return true; 577 return true;
586 578
@@ -588,93 +580,65 @@ struct klass
588 580
589 auto inherit_name = name_helpers::klass_concrete_name(cls); 581 auto inherit_name = name_helpers::klass_concrete_name(cls);
590 582
583 std::string events_gchandle;
584 if (cls.get_all_events().size() > 0)
585 {
586 auto events_gchandle_sink = std::back_inserter(events_gchandle);
587 if (!as_generator(scope_tab << scope_tab << scope_tab << "if (eoEvents.Count != 0)\n"
588 << scope_tab << scope_tab << scope_tab << "{\n"
589 << scope_tab << scope_tab << scope_tab << scope_tab << "GCHandle gcHandle = GCHandle.Alloc(eoEvents);\n"
590 << scope_tab << scope_tab << scope_tab << scope_tab << "gcHandlePtr = GCHandle.ToIntPtr(gcHandle);\n"
591 << scope_tab << scope_tab << scope_tab << "}\n\n")
592 .generate(events_gchandle_sink, attributes::unused, context))
593 return false;
594 }
595
591 return as_generator( 596 return as_generator(
592 597
593 scope_tab << "///<summary>Destructor.</summary>\n" 598 scope_tab << "///<summary>Destructor.</summary>\n"
594 << scope_tab << "~" << inherit_name << "()\n" 599 << scope_tab << "~" << inherit_name << "()\n"
595 << scope_tab << "{\n" 600 << scope_tab << "{\n"
596 << scope_tab << scope_tab << "Dispose(false);\n" 601 << scope_tab << scope_tab << "Dispose(false);\n"
597 << scope_tab << "}\n" 602 << scope_tab << "}\n\n"
598 603
599 << scope_tab << "///<summary>Releases the underlying native instance.</summary>\n" 604 << scope_tab << "///<summary>Releases the underlying native instance.</summary>\n"
600 << scope_tab << visibility << "void Dispose(bool disposing)\n" 605 << scope_tab << visibility << "void Dispose(bool disposing)\n"
601 << scope_tab << "{\n" 606 << scope_tab << "{\n"
602 << scope_tab << scope_tab << "if (handle != System.IntPtr.Zero) {\n" 607 << scope_tab << scope_tab << "if (handle != System.IntPtr.Zero)\n"
608 << scope_tab << scope_tab << "{\n"
609 << scope_tab << scope_tab << scope_tab << "IntPtr h = handle;\n"
610 << scope_tab << scope_tab << scope_tab << "handle = IntPtr.Zero;\n\n"
611
612 << scope_tab << scope_tab << scope_tab << "IntPtr gcHandlePtr = IntPtr.Zero;\n"
613 << events_gchandle
614
603 << scope_tab << scope_tab << scope_tab << "if (disposing)\n" 615 << scope_tab << scope_tab << scope_tab << "if (disposing)\n"
604 << scope_tab << scope_tab << scope_tab << "{\n" 616 << scope_tab << scope_tab << scope_tab << "{\n"
605 << scope_tab << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.efl_unref(handle);\n" 617 << scope_tab << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.efl_mono_native_dispose(h, gcHandlePtr);\n"
606 << scope_tab << scope_tab << scope_tab << "}\n" 618 << scope_tab << scope_tab << scope_tab << "}\n"
607 << scope_tab << scope_tab << scope_tab << "else\n" 619 << scope_tab << scope_tab << scope_tab << "else\n"
608 << scope_tab << scope_tab << scope_tab << "{\n" 620 << scope_tab << scope_tab << scope_tab << "{\n"
609 << scope_tab << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.efl_mono_thread_safe_efl_unref(handle);\n" 621
622 << scope_tab << scope_tab << scope_tab << scope_tab << "Monitor.Enter(Efl.Eo.Config.InitLock);\n"
623 << scope_tab << scope_tab << scope_tab << scope_tab << "if (Efl.Eo.Config.Initialized)\n"
624 << scope_tab << scope_tab << scope_tab << scope_tab << "{\n"
625 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.efl_mono_thread_safe_native_dispose(h, gcHandlePtr);\n"
626 << scope_tab << scope_tab << scope_tab << scope_tab << "}\n\n"
627 << scope_tab << scope_tab << scope_tab << scope_tab << "Monitor.Exit(Efl.Eo.Config.InitLock);\n"
610 << scope_tab << scope_tab << scope_tab << "}\n" 628 << scope_tab << scope_tab << scope_tab << "}\n"
611 << scope_tab << scope_tab << scope_tab << "handle = System.IntPtr.Zero;\n"
612 << scope_tab << scope_tab << "}\n" 629 << scope_tab << scope_tab << "}\n"
613 << scope_tab << "}\n" 630 << scope_tab << "}\n\n"
614 631
615 << scope_tab << "///<summary>Releases the underlying native instance.</summary>\n" 632 << scope_tab << "///<summary>Releases the underlying native instance.</summary>\n"
616 << scope_tab << "public void Dispose()\n" 633 << scope_tab << "public void Dispose()\n"
617 << scope_tab << "{\n" 634 << scope_tab << "{\n"
618 << scope_tab << scope_tab << "Dispose(true);\n" 635 << scope_tab << scope_tab << "Dispose(true);\n"
619 << scope_tab << scope_tab << "GC.SuppressFinalize(this);\n" 636 << scope_tab << scope_tab << "GC.SuppressFinalize(this);\n"
620 << scope_tab << "}\n" 637 << scope_tab << "}\n\n"
621 ).generate(sink, attributes::unused, context); 638 ).generate(sink, attributes::unused, context);
622 } 639 }
623 640
624 template <typename OutputIterator, typename Context> 641 template <typename OutputIterator, typename Context>
625 bool generate_events_registration(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const
626 {
627 bool root = !helpers::has_regular_ancestor(cls);
628 std::string virtual_modifier = " ";
629
630 if (!root)
631 virtual_modifier = "override ";
632 else
633 {
634 if (is_inherit_context(context))
635 virtual_modifier = "virtual ";
636 }
637
638 // Event proxy registration
639 if (!as_generator(
640 scope_tab << "///<summary>Register the Eo event wrappers making the bridge to C# events. Internal usage only.</summary>\n"
641 << scope_tab << (is_inherit_context(context) || !root ? "protected " : "") << virtual_modifier << "void RegisterEventProxies()\n"
642 << scope_tab << "{\n"
643 )
644 .generate(sink, NULL, context))
645 return false;
646
647 // Generate event registrations here
648
649 if (!root)
650 if (!as_generator(scope_tab << scope_tab << "base.RegisterEventProxies();\n").generate(sink, NULL, context))
651 return false;
652
653 // Assigning the delegates
654 if (!as_generator(*(event_registration(cls, cls))).generate(sink, cls.events, context))
655 return false;
656
657 for (auto&& c : helpers::non_implemented_interfaces(cls, context))
658 {
659 // Only non-regular types (which declare events through interfaces) need to register them.
660 if (c.type == attributes::class_type::regular)
661 continue;
662
663 attributes::klass_def klass(get_klass(c, cls.unit), cls.unit);
664
665 if (!as_generator(*(event_registration(klass, cls))).generate(sink, klass.events, context))
666 return false;
667 }
668
669 if (!as_generator(
670 scope_tab << "}\n"
671 ).generate(sink, NULL, context))
672 return false;
673
674 return true;
675 }
676
677 template <typename OutputIterator, typename Context>
678 bool generate_events(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const 642 bool generate_events(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const
679 { 643 {
680 644
@@ -685,69 +649,70 @@ struct klass
685 649
686 if (!helpers::has_regular_ancestor(cls)) 650 if (!helpers::has_regular_ancestor(cls))
687 { 651 {
688 if (!as_generator(scope_tab << visibility << "readonly object eventLock = new object();\n"
689 << scope_tab << visibility << "Dictionary<string, int> event_cb_count = new Dictionary<string, int>();\n")
690 .generate(sink, NULL, context))
691 return false;
692
693 // Callback registration functions 652 // Callback registration functions
694 if (!as_generator( 653 if (!as_generator(
695 scope_tab << "///<summary>Adds a new event handler, registering it to the native event. For internal use only.</summary>\n" 654 scope_tab << "///<summary>Adds a new event handler, registering it to the native event. For internal use only.</summary>\n"
696 << scope_tab << "///<param name=\"lib\">The name of the native library definining the event.</param>\n" 655 << scope_tab << "///<param name=\"lib\">The name of the native library definining the event.</param>\n"
697 << scope_tab << "///<param name=\"key\">The name of the native event.</param>\n" 656 << scope_tab << "///<param name=\"key\">The name of the native event.</param>\n"
698 << scope_tab << "///<param name=\"evt_delegate\">The delegate to be called on event raising.</param>\n" 657 << scope_tab << "///<param name=\"evtCaller\">Delegate to be called by native code on event raising.</param>\n"
699 << scope_tab << "///<returns>True if the delegate was successfully registered.</returns>\n" 658 << scope_tab << "///<param name=\"evtDelegate\">Managed delegate that will be called by evtCaller on event raising.</param>\n"
700 << scope_tab << visibility << "bool AddNativeEventHandler(string lib, string key, Efl.EventCb evt_delegate) {\n" 659 << scope_tab << visibility << "void AddNativeEventHandler(string lib, string key, Efl.EventCb evtCaller, object evtDelegate)\n"
701 << scope_tab << scope_tab << "int event_count = 0;\n" 660 << scope_tab << "{\n"
702 << scope_tab << scope_tab << "if (!event_cb_count.TryGetValue(key, out event_count))\n" 661
703 << scope_tab << scope_tab << scope_tab << "event_cb_count[key] = event_count;\n" 662 << scope_tab << scope_tab << "IntPtr desc = Efl.EventDescription.GetNative(lib, key);\n"
704 << scope_tab << scope_tab << "if (event_count == 0) {\n" 663 << scope_tab << scope_tab << "if (desc == IntPtr.Zero)\n"
705 664 << scope_tab << scope_tab << "{\n"
706 << scope_tab << scope_tab << scope_tab << "IntPtr desc = Efl.EventDescription.GetNative(lib, key);\n" 665 << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to get native event {key}\");\n"
707 << scope_tab << scope_tab << scope_tab << "if (desc == IntPtr.Zero) {\n" 666 << scope_tab << scope_tab << "}\n\n"
708 << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to get native event {key}\");\n" 667
709 << scope_tab << scope_tab << scope_tab << scope_tab << "return false;\n" 668 << scope_tab << scope_tab << "if (eoEvents.ContainsKey((desc, evtDelegate)))\n"
710 << scope_tab << scope_tab << scope_tab << "}\n" 669 << scope_tab << scope_tab << "{\n"
711 670 << scope_tab << scope_tab << scope_tab << "Eina.Log.Warning($\"Event proxy for event {key} already registered!\");\n"
712 << scope_tab << scope_tab << scope_tab << " bool result = Efl.Eo.Globals.efl_event_callback_priority_add(handle, desc, 0, evt_delegate, System.IntPtr.Zero);\n" 671 << scope_tab << scope_tab << scope_tab << "return;\n"
713 << scope_tab << scope_tab << scope_tab << "if (!result) {\n" 672 << scope_tab << scope_tab << "}\n\n"
714 << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to add event proxy for event {key}\");\n" 673
715 << scope_tab << scope_tab << scope_tab << scope_tab << "return false;\n" 674 << scope_tab << scope_tab << "IntPtr evtCallerPtr = Marshal.GetFunctionPointerForDelegate(evtCaller);\n"
716 << scope_tab << scope_tab << scope_tab << "}\n" 675 << scope_tab << scope_tab << "if (!Efl.Eo.Globals.efl_event_callback_priority_add(handle, desc, 0, evtCallerPtr, IntPtr.Zero))\n"
717 << scope_tab << scope_tab << scope_tab << "Eina.Error.RaiseIfUnhandledException();\n" 676 << scope_tab << scope_tab << "{\n"
718 << scope_tab << scope_tab << "} \n" 677 << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to add event proxy for event {key}\");\n"
719 << scope_tab << scope_tab << "event_cb_count[key]++;\n" 678 << scope_tab << scope_tab << scope_tab << "return;\n"
720 << scope_tab << scope_tab << "return true;\n" 679 << scope_tab << scope_tab << "}\n\n"
721 << scope_tab << "}\n" 680
681 << scope_tab << scope_tab << "eoEvents[(desc, evtDelegate)] = (evtCallerPtr, evtCaller);\n"
682 << scope_tab << scope_tab << "Eina.Error.RaiseIfUnhandledException();\n"
683 << scope_tab << "}\n\n"
684
722 << scope_tab << "///<summary>Removes the given event handler for the given event. For internal use only.</summary>\n" 685 << scope_tab << "///<summary>Removes the given event handler for the given event. For internal use only.</summary>\n"
686 << scope_tab << "///<param name=\"lib\">The name of the native library definining the event.</param>\n"
723 << scope_tab << "///<param name=\"key\">The name of the native event.</param>\n" 687 << scope_tab << "///<param name=\"key\">The name of the native event.</param>\n"
724 << scope_tab << "///<param name=\"evt_delegate\">The delegate to be removed.</param>\n" 688 << scope_tab << "///<param name=\"evtDelegate\">The delegate to be removed.</param>\n"
725 << scope_tab << "///<returns>True if the delegate was successfully registered.</returns>\n" 689 << scope_tab << visibility << "void RemoveNativeEventHandler(string lib, string key, object evtDelegate)\n"
726 << scope_tab << visibility << "bool RemoveNativeEventHandler(string key, Efl.EventCb evt_delegate) {\n" 690 << scope_tab << "{\n"
727 << scope_tab << scope_tab << "int event_count = 0;\n" 691
728 << scope_tab << scope_tab << "if (!event_cb_count.TryGetValue(key, out event_count))\n" 692 << scope_tab << scope_tab << "IntPtr desc = Efl.EventDescription.GetNative(lib, key);\n"
729 << scope_tab << scope_tab << scope_tab << "event_cb_count[key] = event_count;\n" 693 << scope_tab << scope_tab << "if (desc == IntPtr.Zero)\n"
730 << scope_tab << scope_tab << "if (event_count == 1) {\n" 694 << scope_tab << scope_tab << "{\n"
731 695 << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to get native event {key}\");\n"
732 << scope_tab << scope_tab << scope_tab << "IntPtr desc = Efl.EventDescription.GetNative(" 696 << scope_tab << scope_tab << scope_tab << "return;\n"
733 << context_find_tag<library_context>(context).actual_library_name(cls.filename) << ", key);\n" 697 << scope_tab << scope_tab << "}\n\n"
734 << scope_tab << scope_tab << scope_tab << "if (desc == IntPtr.Zero) {\n" 698
735 << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to get native event {key}\");\n" 699 << scope_tab << scope_tab << "var evtPair = (desc, evtDelegate);\n"
736 << scope_tab << scope_tab << scope_tab << scope_tab << "return false;\n" 700 << scope_tab << scope_tab << "if (eoEvents.TryGetValue(evtPair, out var caller))\n"
737 << scope_tab << scope_tab << scope_tab << "}\n" 701 << scope_tab << scope_tab << "{\n"
738 702
739 << scope_tab << scope_tab << scope_tab << "bool result = Efl.Eo.Globals.efl_event_callback_del(handle, desc, evt_delegate, System.IntPtr.Zero);\n" 703 << scope_tab << scope_tab << scope_tab << "if (!Efl.Eo.Globals.efl_event_callback_del(handle, desc, caller.evtCallerPtr, IntPtr.Zero))\n"
740 << scope_tab << scope_tab << scope_tab << "if (!result) {\n" 704 << scope_tab << scope_tab << scope_tab << "{\n"
741 << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to remove event proxy for event {key}\");\n" 705 << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to remove event proxy for event {key}\");\n"
742 << scope_tab << scope_tab << scope_tab << scope_tab << "return false;\n" 706 << scope_tab << scope_tab << scope_tab << scope_tab << "return;\n"
743 << scope_tab << scope_tab << scope_tab << "}\n" 707 << scope_tab << scope_tab << scope_tab << "}\n\n"
708
709 << scope_tab << scope_tab << scope_tab << "eoEvents.Remove(evtPair);\n"
744 << scope_tab << scope_tab << scope_tab << "Eina.Error.RaiseIfUnhandledException();\n" 710 << scope_tab << scope_tab << scope_tab << "Eina.Error.RaiseIfUnhandledException();\n"
745 << scope_tab << scope_tab << "} else if (event_count == 0) {\n" 711 << scope_tab << scope_tab << "}\n"
746 << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Trying to remove proxy for event {key} when there is nothing registered.\");\n" 712 << scope_tab << scope_tab << "else\n"
747 << scope_tab << scope_tab << scope_tab << "return false;\n" 713 << scope_tab << scope_tab << "{\n"
748 << scope_tab << scope_tab << "} \n" 714 << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Trying to remove proxy for event {key} when it is nothing registered.\");\n"
749 << scope_tab << scope_tab << "event_cb_count[key]--;\n" 715 << scope_tab << scope_tab << "}\n"
750 << scope_tab << scope_tab << "return true;\n"
751 << scope_tab << "}\n" 716 << scope_tab << "}\n"
752 ) 717 )
753 .generate(sink, NULL, context)) 718 .generate(sink, NULL, context))
diff --git a/src/bin/eolian_mono/eolian_mono.cc b/src/bin/eolian_mono/eolian_mono.cc
index 0699c774e7..f387a3d93e 100644
--- a/src/bin/eolian_mono/eolian_mono.cc
+++ b/src/bin/eolian_mono/eolian_mono.cc
@@ -134,6 +134,7 @@ run(options_type const& opts)
134 "using System.Runtime.InteropServices;\n" 134 "using System.Runtime.InteropServices;\n"
135 "using System.Collections.Generic;\n" 135 "using System.Collections.Generic;\n"
136 "using System.Linq;\n" 136 "using System.Linq;\n"
137 "using System.Threading;\n"
137 "using System.ComponentModel;\n") 138 "using System.ComponentModel;\n")
138 .generate(iterator, efl::eolian::grammar::attributes::unused, efl::eolian::grammar::context_null())) 139 .generate(iterator, efl::eolian::grammar::attributes::unused, efl::eolian::grammar::context_null()))
139 { 140 {