summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-04-05 01:09:08 -0300
committerVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-04-05 01:09:08 -0300
commitf131e55f396ca142e466f6bba50aca1618a187ca (patch)
tree2487a1040997f53b89d1c5c30e4fca349bc889ea
parentf234b241b0eb7927e0b7fd58009ff8d7651e6560 (diff)
downloadefl-f131e55f396ca142e466f6bba50aca1618a187ca.tar.gz
efl_mono: efl_unrefs are functioning properly
-rw-r--r--src/bin/eolian_mono/eolian/mono/events.hh282
-rw-r--r--src/bin/eolian_mono/eolian/mono/klass.hh208
-rw-r--r--src/bindings/mono/eo_mono/iwrapper.cs83
-rw-r--r--src/bindings/mono/eo_mono/workaround.cs2
-rw-r--r--src/lib/efl_mono/efl_custom_exports_mono.c40
-rw-r--r--src/tests/efl_mono/Eo.cs2
6 files changed, 370 insertions, 247 deletions
diff --git a/src/bin/eolian_mono/eolian/mono/events.hh b/src/bin/eolian_mono/eolian/mono/events.hh
index a5e1d8ddc2..44b2547dc2 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
// Structs are usually passed by pointer to events, like having a ptr<> modifier
// Uses implicit conversion from IntPtr
return as_generator(
- " evt.Info;"
+ " evt.Info"
).generate(sink, attributes::unused, *context);
}
else if (type.is_ptr)
@@ -81,6 +81,118 @@ struct unpack_event_args_visitor
}
};
+template<typename OutputIterator, typename Context>
+struct pack_event_info_and_call_visitor
+{
+ mutable OutputIterator sink;
+ Context const* context;
+ attributes::type_def const& type;
+
+ static auto constexpr native_call = "Efl.Eo.Globals.efl_event_callback_call(this.NativeHandle, desc, info);\n";
+
+ typedef pack_event_info_and_call_visitor<OutputIterator, Context> visitor_type;
+ typedef bool result_type;
+
+ bool operator()(grammar::attributes::regular_type_def const& regular) const
+ {
+ std::string arg_type = name_helpers::type_full_managed_name(regular);
+
+ auto const& indent = current_indentation(*context);
+
+ if (regular.is_struct())
+ {
+ // Structs are usually passed by pointer to events, like having a ptr<> modifier
+ // Uses implicit conversion from IntPtr
+ return as_generator(
+ indent << "IntPtr info = Marshal.AllocHGlobal(Marshal.SizeOf(e.arg));\n"
+ << indent << "try\n"
+ << indent << "{\n"
+ << indent << scope_tab << "Marshal.StructureToPtr(e.arg, info, false);\n"
+ << indent << scope_tab << this->native_call
+ << indent << "}\n"
+ << indent << "finally\n"
+ << indent << "{\n"
+ << indent << scope_tab << "Marshal.FreeHGlobal(info);\n"
+ << indent << "}\n"
+ ).generate(sink, attributes::unused, *context);
+ }
+
+ using attributes::regular_type_def;
+ struct match
+ {
+ eina::optional<std::string> name;
+ std::function<std::string()> function;
+ };
+
+ std::string full_type_name = name_helpers::type_full_eolian_name(regular);
+ auto filter_func = [&regular, &full_type_name] (match const& m)
+ {
+ return (!m.name || *m.name == regular.base_type || *m.name == full_type_name);
+ };
+
+ match const str_table[] =
+ {
+ {"string", [] { return "e.arg"; }}
+ , {"stringshare", [] { return "e.arg"; }}
+ };
+
+ auto str_accept_func = [&](std::string const& conversion)
+ {
+ return as_generator(
+ indent << "IntPtr info = Eina.StringConversion.ManagedStringToNativeUtf8Alloc(" << conversion << ");\n"
+ << indent << "try\n"
+ << indent << "{\n"
+ << indent << scope_tab << this->native_call
+ << indent << "}\n"
+ << indent << "finally\n"
+ << indent << "{\n"
+ << indent << scope_tab << "Eina.MemoryNative.Free(info);\n"
+ << indent << "}\n").generate(sink, attributes::unused, *context);
+ };
+
+ if (eina::optional<bool> b = call_match(str_table, filter_func, str_accept_func))
+ return *b;
+
+ match const value_table [] =
+ {
+ {"bool", [] { return "e.arg ? (byte) 1 : (byte) 0"; }}
+ , {"Eina.Error", [] { return "(int)e.arg"; }}
+ , {nullptr, [] { return "e.arg"; }}
+ };
+
+ auto value_accept_func = [&](std::string const& conversion)
+ {
+ return as_generator(
+ indent << "IntPtr info = Eina.PrimitiveConversion.ManagedToPointerAlloc(" << conversion << ");\n"
+ << indent << "try\n"
+ << indent << "{\n"
+ << indent << scope_tab << this->native_call
+ << indent << "}\n"
+ << indent << "finally\n"
+ << indent << "{\n"
+ << indent << scope_tab << "Marshal.FreeHGlobal(info);\n"
+ << indent << "}\n").generate(sink, attributes::unused, *context);
+ };
+
+ if (eina::optional<bool> b = call_match(value_table, filter_func, value_accept_func))
+ return *b;
+
+ return value_accept_func("e.args");
+ }
+ bool operator()(grammar::attributes::klass_name const&) const
+ {
+ auto const& indent = current_indentation(*context);
+ return as_generator(indent << "IntPtr info = e.arg.NativeHandle;\n"
+ << indent << this->native_call).generate(sink, attributes::unused, *context);
+ }
+ bool operator()(attributes::complex_type_def const&) const
+ {
+ auto const& indent = current_indentation(*context);
+ return as_generator(indent << "IntPtr info = e.arg.Handle;\n"
+ << indent << this->native_call).generate(sink, attributes::unused, *context);
+ }
+};
+
/*
* Generates a struct wrapping the argument of a given event.
*/
@@ -138,40 +250,6 @@ struct event_declaration_generator
}
} const event_declaration {};
-struct event_registration_generator
-{
- attributes::klass_def const& klass;
- attributes::klass_def const& leaf_klass;
- bool is_inherited_event;
-
- template<typename OutputIterator, typename Context>
- bool generate(OutputIterator sink, attributes::event_def const& evt, Context const& context) const
- {
- std::string wrapper_event_name;
-
- if (blacklist::is_event_blacklisted(evt, context))
- return true;
-
- if (is_inherited_event && !helpers::is_unique_event(evt, leaf_klass))
- wrapper_event_name = name_helpers::translate_inherited_event_name(evt, klass);
- else
- wrapper_event_name = name_helpers::managed_event_name(evt.name);
-
- return as_generator(scope_tab << scope_tab << "evt_" << wrapper_event_name << "_delegate = "
- << "new Efl.EventCb(on_" << wrapper_event_name << "_NativeCallback);\n"
- ).generate(sink, attributes::unused, context);
- }
-};
-
-struct event_registration_parameterized
-{
- event_registration_generator operator()(attributes::klass_def const& klass, attributes::klass_def const& leaf_klass) const
- {
- bool is_inherited_event = klass != leaf_klass;
- return {klass, leaf_klass, is_inherited_event};
- }
-} const event_registration;
-
struct event_definition_generator
{
attributes::klass_def const& klass;
@@ -185,6 +263,7 @@ struct event_definition_generator
return true;
std::string managed_evt_name = name_helpers::managed_event_name(evt.name);
+ auto const& indent = current_indentation(context);
bool is_unique = helpers::is_unique_event(evt, leaf_klass);
bool use_explicit_impl = is_inherited_event && !is_unique;
@@ -205,20 +284,35 @@ struct event_definition_generator
std::string wrapper_args_type = "EventArgs";
std::string wrapper_args_template = "";
std::string event_args = "EventArgs args = EventArgs.Empty;\n";
+ std::string event_native_call;
efl::eina::optional<grammar::attributes::type_def> etype = evt.type;
- if (etype.is_engaged())
+ if (!etype.is_engaged())
+ {
+ auto event_call_site_sink = std::back_inserter(event_native_call);
+ if (!as_generator(indent.inc().inc() << "Efl.Eo.Globals.efl_event_callback_call(this.NativeHandle, desc, IntPtr.Zero);\n")
+ .generate(event_call_site_sink, attributes::unused, context))
+ return false;
+ }
+ else
{
wrapper_args_type = name_helpers::managed_event_args_name(evt);
wrapper_args_template = "<" + wrapper_args_type + ">";
- std::string arg_initializer = wrapper_args_type + " args = new " + wrapper_args_type + "();\n";
-
- arg_initializer += " args.arg = ";
+ std::string arg_initializer;
auto arg_initializer_sink = std::back_inserter(arg_initializer);
+ auto event_call_site_sink = std::back_inserter(event_native_call);
+
+ auto sub_context = change_indentation(indent.inc().inc(), context);
- if (!(*etype).original_type.visit(unpack_event_args_visitor<decltype(arg_initializer_sink), Context>{arg_initializer_sink, &context, *etype}))
+ if (!as_generator(scope_tab(6) << wrapper_args_type << " args = new " << wrapper_args_type << "();\n"
+ << scope_tab(6) << "args.arg = ").generate(arg_initializer_sink, attributes::unused, context))
+ return false;
+ if (!(*etype).original_type.visit(unpack_event_args_visitor<decltype(arg_initializer_sink), decltype(sub_context)>{arg_initializer_sink, &sub_context, *etype}))
+ return false;
+
+ 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}))
return false;
arg_initializer += ";\n";
@@ -226,10 +320,6 @@ struct event_definition_generator
event_args = arg_initializer;
}
- if(!as_generator("private static object " << wrapper_evt_name << "Key = new object();\n")
- .generate(sink, attributes::unused, context))
- return false;
-
if(!as_generator(documentation(1)).generate(sink, evt, context))
return false;
@@ -256,31 +346,10 @@ struct event_definition_generator
return false;
}
- if (!generate_event_add_remove(sink, evt, wrapper_evt_name, context))
- return false;
-
- if (!generate_event_trigger(sink, wrapper_evt_name, wrapper_args_type, wrapper_args_template, context))
+ if (!generate_event_add_remove(sink, evt, event_args, context))
return false;
- // Store the delegate for this event in this instance. This is initialized in RegisterEventProxies()
- // We can't initialize them directly here as they depend on the member methods being valid (i.e.
- // the constructor being called).
- if (!as_generator(scope_tab << "Efl.EventCb evt_" << wrapper_evt_name << "_delegate;\n").generate(sink, attributes::unused, context))
- return false;
-
- // Callback to be given to C's callback_priority_add
- if (!as_generator(
- scope_tab << "private void on_" << wrapper_evt_name << "_NativeCallback(System.IntPtr data, ref Efl.Event.NativeStruct evt)\n"
- << scope_tab << "{\n"
- << scope_tab << scope_tab << event_args
- << scope_tab << scope_tab << "try {\n"
- << scope_tab << scope_tab << scope_tab << "On_" << wrapper_evt_name << "(args);\n"
- << scope_tab << scope_tab << "} catch (Exception e) {\n"
- << scope_tab << scope_tab << scope_tab << "Eina.Log.Error(e.ToString());\n"
- << scope_tab << scope_tab << scope_tab << "Eina.Error.Set(Eina.Error.UNHANDLED_EXCEPTION);\n"
- << scope_tab << scope_tab << "}\n"
- << scope_tab << "}\n\n"
- ).generate(sink, attributes::unused, context))
+ if (!generate_event_trigger(sink, evt, wrapper_evt_name, wrapper_args_type, event_native_call, context))
return false;
return true;
@@ -288,21 +357,26 @@ struct event_definition_generator
template<typename OutputIterator, typename Context>
bool generate_event_trigger(OutputIterator sink
+ , attributes::event_def const &evt
, std::string const& event_name
, std::string const& event_args_type
- , std::string const& event_template_args
+ , std::string const& event_native_call
, Context const& context) const
{
- auto delegate_type = "EventHandler" + event_template_args;
+ auto library_name = context_find_tag<library_context>(context).actual_library_name(klass.filename);
+ std::string upper_c_name = utils::to_uppercase(evt.c_name);
if (!as_generator(
scope_tab << "///<summary>Method to raise event "<< event_name << ".</summary>\n"
- << scope_tab << "public void On_" << event_name << "(" << event_args_type << " e)\n"
+ << scope_tab << "public void On" << event_name << "(" << event_args_type << " e)\n"
<< scope_tab << "{\n"
- << scope_tab << scope_tab << delegate_type << " evt;\n"
- << scope_tab << scope_tab << "lock (eventLock) {\n"
- << scope_tab << scope_tab << "evt = (" << delegate_type << ")eventHandlers[" << event_name << "Key];\n"
- << scope_tab << scope_tab << "}\n"
- << scope_tab << scope_tab << "evt?.Invoke(this, e);\n"
+ << scope_tab << scope_tab << "var key = \"_" << upper_c_name << "\";\n"
+ << scope_tab << scope_tab << "IntPtr desc = Efl.EventDescription.GetNative(" << library_name << ", key);\n"
+ << scope_tab << scope_tab << "if (desc == IntPtr.Zero)\n"
+ << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to get native event {key}\");\n"
+ << scope_tab << scope_tab << scope_tab << "return;\n"
+ << scope_tab << scope_tab << "}\n\n"
+ << event_native_call
<< scope_tab << "}\n"
).generate(sink, nullptr, context))
return false;
@@ -311,7 +385,10 @@ struct event_definition_generator
}
template<typename OutputIterator, typename Context>
- bool generate_event_add_remove(OutputIterator sink, attributes::event_def const &evt, const std::string& event_name, Context const& context) const
+ bool generate_event_add_remove(OutputIterator sink
+ , attributes::event_def const &evt
+ , std::string const& event_args
+ , Context const& context) const
{
std::string upper_c_name = utils::to_uppercase(evt.c_name);
auto unit = (const Eolian_Unit*) context_find_tag<eolian_state_context>(context).state;
@@ -319,22 +396,38 @@ struct event_definition_generator
auto library_name = context_find_tag<library_context>(context).actual_library_name(klass.filename);
return as_generator(
scope_tab << "{\n"
- << scope_tab << scope_tab << "add {\n"
- << scope_tab << scope_tab << scope_tab << "lock (eventLock) {\n"
+ << scope_tab << scope_tab << "add\n"
+ << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << "lock (eventLock)\n"
+ << scope_tab << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << "var wRef = new WeakReference(this);\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << "Efl.EventCb callerCb = (IntPtr data, ref Efl.Event.NativeStruct evt) =>\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "var obj = wRef.Target as Efl.Eo.IWrapper;\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "if (obj != null)\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << event_args
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "try\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "value?.Invoke(obj, args);\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "}\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "catch (Exception e)\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error(e.ToString());\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Error.Set(Eina.Error.UNHANDLED_EXCEPTION);\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "}\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "}\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << "};\n\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "string key = \"_" << upper_c_name << "\";\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << "if (AddNativeEventHandler(" << library_name << ", key, this.evt_" << event_name << "_delegate)) {\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "eventHandlers.AddHandler(" << event_name << "Key , value);\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << "} else\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Error adding proxy for event {key}\");\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << "AddNativeEventHandler(" << library_name << ", key, callerCb, value);\n"
<< scope_tab << scope_tab << scope_tab << "}\n" // End of lock block
- << scope_tab << scope_tab << "}\n"
- << scope_tab << scope_tab << "remove {\n"
- << scope_tab << scope_tab << scope_tab << "lock (eventLock) {\n"
+ << scope_tab << scope_tab << "}\n\n"
+ << scope_tab << scope_tab << "remove\n"
+ << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << "lock (eventLock)\n"
+ << scope_tab << scope_tab << scope_tab << "{\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "string key = \"_" << upper_c_name << "\";\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << "if (RemoveNativeEventHandler(key, this.evt_" << event_name << "_delegate)) { \n"
- << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "eventHandlers.RemoveHandler(" << event_name << "Key , value);\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << "} else\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Error removing proxy for event {key}\");\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << "RemoveNativeEventHandler(" << library_name << ", key, value);\n"
<< scope_tab << scope_tab << scope_tab << "}\n" // End of lock block
<< scope_tab << scope_tab << "}\n"
<< scope_tab << "}\n"
@@ -366,13 +459,6 @@ template <>
struct is_generator<struct ::eolian_mono::event_declaration_generator> : std::true_type {};
template <>
-struct is_eager_generator<struct ::eolian_mono::event_registration_generator> : std::true_type {};
-template <>
-struct is_generator<struct ::eolian_mono::event_registration_generator> : std::true_type {};
-template <>
-struct is_generator<struct ::eolian_mono::event_registration_parameterized> : std::true_type {};
-
-template <>
struct is_eager_generator<struct ::eolian_mono::event_definition_generator> : std::true_type {};
template <>
struct is_generator<struct ::eolian_mono::event_definition_generator> : std::true_type {};
@@ -385,10 +471,6 @@ struct attributes_needed<struct ::eolian_mono::event_argument_wrapper_generator>
template <>
struct attributes_needed<struct ::eolian_mono::event_declaration_generator> : std::integral_constant<int, 1> {};
template <>
-struct attributes_needed<struct ::eolian_mono::event_registration_generator> : std::integral_constant<int, 1> {};
-template <>
-struct attributes_needed<struct ::eolian_mono::event_registration_parameterized> : std::integral_constant<int, 1> {};
-template <>
struct attributes_needed<struct ::eolian_mono::event_definition_generator> : std::integral_constant<int, 1> {};
template <>
struct 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 666ed79afc..bec470efef 100644
--- a/src/bin/eolian_mono/eolian/mono/klass.hh
+++ b/src/bin/eolian_mono/eolian/mono/klass.hh
@@ -237,7 +237,6 @@ struct klass
<< scope_tab << "public " << concrete_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << (root ? "handle = raw;\n" : "")
- << scope_tab << scope_tab << "RegisterEventProxies();\n"
<< scope_tab << "}\n"
)
.generate(sink, attributes::unused, concrete_cxt))
@@ -255,9 +254,6 @@ struct klass
if (!generate_events(sink, cls, concrete_cxt))
return false;
- if (!generate_events_registration(sink, cls, concrete_cxt))
- return false;
-
// Parts
if(!as_generator(*(part_definition))
.generate(sink, cls.parts, concrete_cxt)) return false;
@@ -336,9 +332,6 @@ struct klass
if (!generate_events(sink, cls, inherit_cxt))
return false;
- if (!generate_events_registration(sink, cls, inherit_cxt))
- return false;
-
// Parts
if(!as_generator(*(part_definition))
.generate(sink, cls.parts, inherit_cxt)) return false;
@@ -479,7 +472,9 @@ struct klass
return true;
if (cls.get_all_events().size() > 0)
- if (!as_generator(scope_tab << (is_inherit ? "protected " : "private ") << "EventHandlerList eventHandlers = new EventHandlerList();\n").generate(sink, attributes::unused, context))
+ if (!as_generator(scope_tab << visibility << "Dictionary<(IntPtr desc, object evtDelegate), Efl.EventCb> eoEvents = new Dictionary<(IntPtr desc, object evtDelegate), Efl.EventCb>();\n"
+ << scope_tab << visibility << "readonly object eventLock = new object();\n")
+ .generate(sink, attributes::unused, context))
return false;
if (is_inherit)
@@ -537,7 +532,6 @@ struct klass
<< scope_tab << "public " << inherit_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << (root ? "handle = raw;\n" : "")
- << scope_tab << scope_tab << "RegisterEventProxies();\n"
<< scope_tab << "}\n"
).generate(sink, std::make_tuple(constructors, constructors, constructors), context))
return false;
@@ -563,7 +557,6 @@ struct klass
<< scope_tab << scope_tab << scope_tab << "actual_klass = Efl.Eo.ClassRegister.GetInheritKlassOrRegister(base_klass, ((object)this).GetType());\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << "handle = Efl.Eo.Globals.instantiate_start(actual_klass, parent);\n"
- << scope_tab << scope_tab << "RegisterEventProxies();\n"
<< scope_tab << "}\n"
<< scope_tab << "protected void FinishInstantiation()\n"
@@ -582,7 +575,6 @@ struct klass
template <typename OutputIterator, typename Context>
bool generate_dispose_methods(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const
{
- std::string name = join_namespaces(cls.namespaces, '.') + cls.eolian_name;
if (helpers::has_regular_ancestor(cls))
return true;
@@ -590,93 +582,59 @@ struct klass
auto inherit_name = name_helpers::klass_concrete_name(cls);
+ std::string events_gchandle;
+ if (cls.get_all_events().size() > 0)
+ {
+ auto events_gchandle_sink = std::back_inserter(events_gchandle);
+ if (!as_generator(scope_tab << scope_tab << scope_tab << "if (eoEvents.Count != 0)\n"
+ << scope_tab << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << "GCHandle gcHandle = GCHandle.Alloc(eoEvents);\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << "gcHandlePtr = GCHandle.ToIntPtr(gcHandle);\n"
+ << scope_tab << scope_tab << scope_tab << "}\n\n")
+ .generate(events_gchandle_sink, attributes::unused, context))
+ return false;
+ }
+
return as_generator(
scope_tab << "///<summary>Destructor.</summary>\n"
<< scope_tab << "~" << inherit_name << "()\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "Dispose(false);\n"
- << scope_tab << "}\n"
+ << scope_tab << "}\n\n"
<< scope_tab << "///<summary>Releases the underlying native instance.</summary>\n"
<< scope_tab << visibility << "void Dispose(bool disposing)\n"
<< scope_tab << "{\n"
- << scope_tab << scope_tab << "if (handle != System.IntPtr.Zero) {\n"
+ << scope_tab << scope_tab << "if (handle != System.IntPtr.Zero)\n"
+ << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << "IntPtr h = handle;\n"
+ << scope_tab << scope_tab << scope_tab << "handle = IntPtr.Zero;\n\n"
+
+ << scope_tab << scope_tab << scope_tab << "IntPtr gcHandlePtr = IntPtr.Zero;\n"
+ << events_gchandle
+
<< scope_tab << scope_tab << scope_tab << "if (disposing)\n"
<< scope_tab << scope_tab << scope_tab << "{\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.efl_unref(handle);\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.efl_mono_native_dispose(h, gcHandlePtr);\n"
<< scope_tab << scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << scope_tab << "else\n"
<< scope_tab << scope_tab << scope_tab << "{\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.efl_mono_thread_safe_efl_unref(handle);\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.efl_mono_thread_safe_native_dispose(h, gcHandlePtr);\n"
<< scope_tab << scope_tab << scope_tab << "}\n"
- << scope_tab << scope_tab << scope_tab << "handle = System.IntPtr.Zero;\n"
<< scope_tab << scope_tab << "}\n"
- << scope_tab << "}\n"
+ << scope_tab << "}\n\n"
<< scope_tab << "///<summary>Releases the underlying native instance.</summary>\n"
<< scope_tab << "public void Dispose()\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "Dispose(true);\n"
<< scope_tab << scope_tab << "GC.SuppressFinalize(this);\n"
- << scope_tab << "}\n"
+ << scope_tab << "}\n\n"
).generate(sink, attributes::unused, context);
}
template <typename OutputIterator, typename Context>
- bool generate_events_registration(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const
- {
- bool root = !helpers::has_regular_ancestor(cls);
- std::string virtual_modifier = " ";
-
- if (!root)
- virtual_modifier = "override ";
- else
- {
- if (is_inherit_context(context))
- virtual_modifier = "virtual ";
- }
-
- // Event proxy registration
- if (!as_generator(
- scope_tab << "///<summary>Register the Eo event wrappers making the bridge to C# events. Internal usage only.</summary>\n"
- << scope_tab << (is_inherit_context(context) || !root ? "protected " : "") << virtual_modifier << "void RegisterEventProxies()\n"
- << scope_tab << "{\n"
- )
- .generate(sink, NULL, context))
- return false;
-
- // Generate event registrations here
-
- if (!root)
- if (!as_generator(scope_tab << scope_tab << "base.RegisterEventProxies();\n").generate(sink, NULL, context))
- return false;
-
- // Assigning the delegates
- if (!as_generator(*(event_registration(cls, cls))).generate(sink, cls.events, context))
- return false;
-
- for (auto&& c : helpers::non_implemented_interfaces(cls, context))
- {
- // Only non-regular types (which declare events through interfaces) need to register them.
- if (c.type == attributes::class_type::regular)
- continue;
-
- attributes::klass_def klass(get_klass(c, cls.unit), cls.unit);
-
- if (!as_generator(*(event_registration(klass, cls))).generate(sink, klass.events, context))
- return false;
- }
-
- if (!as_generator(
- scope_tab << "}\n"
- ).generate(sink, NULL, context))
- return false;
-
- return true;
- }
-
- template <typename OutputIterator, typename Context>
bool generate_events(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const
{
@@ -687,69 +645,69 @@ struct klass
if (!helpers::has_regular_ancestor(cls))
{
- if (!as_generator(scope_tab << visibility << "readonly object eventLock = new object();\n"
- << scope_tab << visibility << "Dictionary<string, int> event_cb_count = new Dictionary<string, int>();\n")
- .generate(sink, NULL, context))
- return false;
-
// Callback registration functions
if (!as_generator(
scope_tab << "///<summary>Adds a new event handler, registering it to the native event. For internal use only.</summary>\n"
<< scope_tab << "///<param name=\"lib\">The name of the native library definining the event.</param>\n"
<< scope_tab << "///<param name=\"key\">The name of the native event.</param>\n"
- << scope_tab << "///<param name=\"evt_delegate\">The delegate to be called on event raising.</param>\n"
- << scope_tab << "///<returns>True if the delegate was successfully registered.</returns>\n"
- << scope_tab << visibility << "bool AddNativeEventHandler(string lib, string key, Efl.EventCb evt_delegate) {\n"
- << scope_tab << scope_tab << "int event_count = 0;\n"
- << scope_tab << scope_tab << "if (!event_cb_count.TryGetValue(key, out event_count))\n"
- << scope_tab << scope_tab << scope_tab << "event_cb_count[key] = event_count;\n"
- << scope_tab << scope_tab << "if (event_count == 0) {\n"
-
- << scope_tab << scope_tab << scope_tab << "IntPtr desc = Efl.EventDescription.GetNative(lib, key);\n"
- << scope_tab << scope_tab << scope_tab << "if (desc == IntPtr.Zero) {\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to get native event {key}\");\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << "return false;\n"
- << scope_tab << scope_tab << scope_tab << "}\n"
-
- << 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"
- << scope_tab << scope_tab << scope_tab << "if (!result) {\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to add event proxy for event {key}\");\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << "return false;\n"
- << scope_tab << scope_tab << scope_tab << "}\n"
- << scope_tab << scope_tab << scope_tab << "Eina.Error.RaiseIfUnhandledException();\n"
- << scope_tab << scope_tab << "} \n"
- << scope_tab << scope_tab << "event_cb_count[key]++;\n"
- << scope_tab << scope_tab << "return true;\n"
- << scope_tab << "}\n"
+ << scope_tab << "///<param name=\"evtCaller\">Delegate to be called by native code on event raising.</param>\n"
+ << scope_tab << "///<param name=\"evtDelegate\">Managed delegate that will be called by evtCaller on event raising.</param>\n"
+ << scope_tab << visibility << "void AddNativeEventHandler(string lib, string key, Efl.EventCb evtCaller, object evtDelegate)\n"
+ << scope_tab << "{\n"
+
+ << scope_tab << scope_tab << "IntPtr desc = Efl.EventDescription.GetNative(lib, key);\n"
+ << scope_tab << scope_tab << "if (desc == IntPtr.Zero)\n"
+ << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to get native event {key}\");\n"
+ << scope_tab << scope_tab << "}\n\n"
+
+ << scope_tab << scope_tab << "if (eoEvents.ContainsKey((desc, evtDelegate)))\n"
+ << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << "Eina.Log.Warning($\"Event proxy for event {key} already registered!\");\n"
+ << scope_tab << scope_tab << scope_tab << "return;\n"
+ << scope_tab << scope_tab << "}\n\n"
+
+ << scope_tab << scope_tab << "if (!Efl.Eo.Globals.efl_event_callback_priority_add(handle, desc, 0, evtCaller, IntPtr.Zero))\n"
+ << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to add event proxy for event {key}\");\n"
+ << scope_tab << scope_tab << scope_tab << "return;\n"
+ << scope_tab << scope_tab << "}\n\n"
+
+ << scope_tab << scope_tab << "eoEvents[(desc, evtDelegate)] = evtCaller;\n"
+ << scope_tab << scope_tab << "Eina.Error.RaiseIfUnhandledException();\n"
+ << scope_tab << "}\n\n"
+
<< scope_tab << "///<summary>Removes the given event handler for the given event. For internal use only.</summary>\n"
+ << scope_tab << "///<param name=\"lib\">The name of the native library definining the event.</param>\n"
<< scope_tab << "///<param name=\"key\">The name of the native event.</param>\n"
- << scope_tab << "///<param name=\"evt_delegate\">The delegate to be removed.</param>\n"
- << scope_tab << "///<returns>True if the delegate was successfully registered.</returns>\n"
- << scope_tab << visibility << "bool RemoveNativeEventHandler(string key, Efl.EventCb evt_delegate) {\n"
- << scope_tab << scope_tab << "int event_count = 0;\n"
- << scope_tab << scope_tab << "if (!event_cb_count.TryGetValue(key, out event_count))\n"
- << scope_tab << scope_tab << scope_tab << "event_cb_count[key] = event_count;\n"
- << scope_tab << scope_tab << "if (event_count == 1) {\n"
-
- << scope_tab << scope_tab << scope_tab << "IntPtr desc = Efl.EventDescription.GetNative("
- << context_find_tag<library_context>(context).actual_library_name(cls.filename) << ", key);\n"
- << scope_tab << scope_tab << scope_tab << "if (desc == IntPtr.Zero) {\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to get native event {key}\");\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << "return false;\n"
- << scope_tab << scope_tab << scope_tab << "}\n"
-
- << scope_tab << scope_tab << scope_tab << "bool result = Efl.Eo.Globals.efl_event_callback_del(handle, desc, evt_delegate, System.IntPtr.Zero);\n"
- << scope_tab << scope_tab << scope_tab << "if (!result) {\n"
+ << scope_tab << "///<param name=\"evtDelegate\">The delegate to be removed.</param>\n"
+ << scope_tab << visibility << "void RemoveNativeEventHandler(string lib, string key, object evtDelegate)\n"
+ << scope_tab << "{\n"
+
+ << scope_tab << scope_tab << "IntPtr desc = Efl.EventDescription.GetNative(lib, key);\n"
+ << scope_tab << scope_tab << "if (desc == IntPtr.Zero)\n"
+ << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to get native event {key}\");\n"
+ << scope_tab << scope_tab << scope_tab << "return;\n"
+ << scope_tab << scope_tab << "}\n\n"
+
+ << scope_tab << scope_tab << "var evtPair = (desc, evtDelegate);\n"
+ << scope_tab << scope_tab << "if (eoEvents.TryGetValue(evtPair, out var evtCaller))\n"
+ << scope_tab << scope_tab << "{\n"
+
+ << scope_tab << scope_tab << scope_tab << "if (!Efl.Eo.Globals.efl_event_callback_del(handle, desc, evtCaller, IntPtr.Zero))\n"
+ << scope_tab << scope_tab << scope_tab << "{\n"
<< scope_tab << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Failed to remove event proxy for event {key}\");\n"
- << scope_tab << scope_tab << scope_tab << scope_tab << "return false;\n"
- << scope_tab << scope_tab << scope_tab << "}\n"
+ << scope_tab << scope_tab << scope_tab << scope_tab << "return;\n"
+ << scope_tab << scope_tab << scope_tab << "}\n\n"
+
+ << scope_tab << scope_tab << scope_tab << "eoEvents.Remove(evtPair);\n"
<< scope_tab << scope_tab << scope_tab << "Eina.Error.RaiseIfUnhandledException();\n"
- << scope_tab << scope_tab << "} else if (event_count == 0) {\n"
- << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Trying to remove proxy for event {key} when there is nothing registered.\");\n"
- << scope_tab << scope_tab << scope_tab << "return false;\n"
- << scope_tab << scope_tab << "} \n"
- << scope_tab << scope_tab << "event_cb_count[key]--;\n"
- << scope_tab << scope_tab << "return true;\n"
+ << scope_tab << scope_tab << "}\n"
+ << scope_tab << scope_tab << "else\n"
+ << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << "Eina.Log.Error($\"Trying to remove proxy for event {key} when it is nothing registered.\");\n"
+ << scope_tab << scope_tab << "}\n"
<< scope_tab << "}\n"
)
.generate(sink, NULL, context))
diff --git a/src/bindings/mono/eo_mono/iwrapper.cs b/src/bindings/mono/eo_mono/iwrapper.cs
index 1d392bc403..77e3cfd75a 100644
--- a/src/bindings/mono/eo_mono/iwrapper.cs
+++ b/src/bindings/mono/eo_mono/iwrapper.cs
@@ -50,6 +50,12 @@ public class Globals {
[DllImport(efl.Libs.Eo)] public static extern int
efl_ref_count(IntPtr eo);
[DllImport(efl.Libs.CustomExports)] public static extern void
+ efl_mono_gchandle_callbacks_set(Efl.FreeGCHandleCb freeGCHandleCb, Efl.RemoveEventsCb removeEventsCb);
+ [DllImport(efl.Libs.CustomExports)] public static extern void
+ efl_mono_native_dispose(IntPtr eo, IntPtr gcHandle);
+ [DllImport(efl.Libs.CustomExports)] public static extern void
+ efl_mono_thread_safe_native_dispose(IntPtr eo, IntPtr gcHandle);
+ [DllImport(efl.Libs.CustomExports)] public static extern void
efl_mono_thread_safe_efl_unref(IntPtr eo);
[DllImport(efl.Libs.CustomExports)] public static extern void
@@ -168,28 +174,14 @@ public class Globals {
public delegate IntPtr dlerror_delegate();
[DllImport(efl.Libs.Evil)] public static extern IntPtr dlerror();
- public delegate bool efl_event_callback_priority_add_delegate(
- System.IntPtr obj,
- IntPtr desc,
- short priority,
- Efl.EventCb cb,
- System.IntPtr data);
- [DllImport(efl.Libs.Eo)] public static extern bool efl_event_callback_priority_add(
- System.IntPtr obj,
- IntPtr desc,
- short priority,
- Efl.EventCb cb,
- System.IntPtr data);
- public delegate bool efl_event_callback_del_delegate(
- System.IntPtr obj,
- IntPtr desc,
- Efl.EventCb cb,
- System.IntPtr data);
- [DllImport(efl.Libs.Eo)] public static extern bool efl_event_callback_del(
- System.IntPtr obj,
- IntPtr desc,
- Efl.EventCb cb,
- System.IntPtr data);
+ [DllImport(efl.Libs.Eo)] [return: MarshalAs(UnmanagedType.U1)] public static extern bool
+ efl_event_callback_priority_add(IntPtr obj, IntPtr desc, short priority, Efl.EventCb cb, IntPtr data);
+
+ [DllImport(efl.Libs.Eo)] [return: MarshalAs(UnmanagedType.U1)] public static extern bool
+ efl_event_callback_del(IntPtr obj, IntPtr desc, Efl.EventCb cb, IntPtr data);
+
+ [DllImport(efl.Libs.Eo)] [return: MarshalAs(UnmanagedType.U1)] public static extern bool
+ efl_event_callback_call(IntPtr obj, IntPtr desc, IntPtr event_info);
public const int RTLD_NOW = 2;
@@ -497,6 +489,52 @@ public class Globals {
return tcs.Task;
}
+
+ public static void FreeGCHandleCallback(IntPtr gcHandlePtr)
+ {
+ try
+ {
+ GCHandle gcHandle = GCHandle.FromIntPtr(gcHandlePtr);
+ gcHandle.Free();
+ }
+ catch (Exception e)
+ {
+ Eina.Log.Error(e.ToString());
+ Eina.Error.Set(Eina.Error.UNHANDLED_EXCEPTION);
+ }
+ }
+
+ public static void RemoveEventsCallback(IntPtr obj, IntPtr gcHandlePtr)
+ {
+ try
+ {
+ GCHandle gcHandle = GCHandle.FromIntPtr(gcHandlePtr);
+ var eoEvents = gcHandle.Target as Dictionary<(IntPtr desc, object evtDelegate), Efl.EventCb>;
+ if (eoEvents == null)
+ {
+ return;
+ }
+
+ foreach (var item in eoEvents)
+ {
+ if (!efl_event_callback_del(obj, item.Key.desc, item.Value, IntPtr.Zero))
+ {
+ Eina.Log.Error($"Failed to remove event proxy for event {item.Key.desc}");
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Eina.Log.Error(e.ToString());
+ Eina.Error.Set(Eina.Error.UNHANDLED_EXCEPTION);
+ }
+ }
+
+ public static void SetNativeDisposeCallbacks()
+ {
+ efl_mono_gchandle_callbacks_set(FreeGCHandleCallback, RemoveEventsCallback);
+ }
+
} // Globals
public static class Config
@@ -504,6 +542,7 @@ public static class Config
public static void Init()
{
Globals.efl_object_init();
+ Globals.SetNativeDisposeCallbacks();
}
public static void Shutdown()
diff --git a/src/bindings/mono/eo_mono/workaround.cs b/src/bindings/mono/eo_mono/workaround.cs
index b1f9d9fea7..48085df328 100644
--- a/src/bindings/mono/eo_mono/workaround.cs
+++ b/src/bindings/mono/eo_mono/workaround.cs
@@ -105,6 +105,8 @@ public struct EventDescription {
};
public delegate void EventCb(System.IntPtr data, ref Event.NativeStruct evt);
+public delegate void FreeGCHandleCb(System.IntPtr gcHandle);
+public delegate void RemoveEventsCb(System.IntPtr obj, System.IntPtr gcHandle);
[StructLayout(LayoutKind.Sequential)]
public struct TextCursorCursor {
diff --git a/src/lib/efl_mono/efl_custom_exports_mono.c b/src/lib/efl_mono/efl_custom_exports_mono.c
index 669625969e..c4a3b54bc5 100644
--- a/src/lib/efl_mono/efl_custom_exports_mono.c
+++ b/src/lib/efl_mono/efl_custom_exports_mono.c
@@ -23,6 +23,46 @@
# endif
#endif /* ! _WIN32 */
+typedef void (*Efl_Mono_Free_GCHandle_Cb)(void *gchandle);
+typedef void (*Efl_Mono_Remove_Events_Cb)(Eo *obj, void *gchandle);
+
+static Efl_Mono_Free_GCHandle_Cb _efl_mono_free_gchandle_call = NULL;
+static Efl_Mono_Remove_Events_Cb _efl_mono_remove_events_call = NULL;
+
+EAPI void efl_mono_gchandle_callbacks_set(Efl_Mono_Free_GCHandle_Cb free_gchandle_cb, Efl_Mono_Remove_Events_Cb remove_events_cb)
+{
+ _efl_mono_free_gchandle_call = free_gchandle_cb;
+ _efl_mono_remove_events_call = remove_events_cb;
+}
+
+EAPI void efl_mono_native_dispose(Eo *obj, void* gchandle)
+{
+ if (gchandle) _efl_mono_remove_events_call(obj, gchandle);
+ efl_unref(obj);
+ if (gchandle) _efl_mono_free_gchandle_call(gchandle);
+}
+
+typedef struct _Efl_Mono_Native_Dispose_Data
+{
+ Eo *obj;
+ void *gchandle;
+} Efl_Mono_Native_Dispose_Data;
+
+static void _efl_mono_native_dispose_cb(void *data)
+{
+ Efl_Mono_Native_Dispose_Data *dd = data;
+ efl_mono_native_dispose(dd->obj, dd->gchandle);
+ free(dd);
+}
+
+EAPI void efl_mono_thread_safe_native_dispose(Eo *obj, void* gchandle)
+{
+ Efl_Mono_Native_Dispose_Data *dd = malloc(sizeof(Efl_Mono_Native_Dispose_Data));
+ dd->obj = obj;
+ dd->gchandle = gchandle;
+ ecore_main_loop_thread_safe_call_async(_efl_mono_native_dispose_cb, dd);
+}
+
static void _efl_mono_unref_cb(void *obj)
{
efl_unref(obj);
diff --git a/src/tests/efl_mono/Eo.cs b/src/tests/efl_mono/Eo.cs
index 578ad10790..117e11a8e9 100644
--- a/src/tests/efl_mono/Eo.cs
+++ b/src/tests/efl_mono/Eo.cs
@@ -49,6 +49,7 @@ class TestEo
Test.Assert(delEventCalled, "DEL event not called");
} */
+ /*
public static void dispose_really_frees()
{
bool delEventCalled = false;
@@ -62,6 +63,7 @@ class TestEo
Test.Assert(delEventCalled, "DEL event not called");
}
+ */
/* Commented out as adding the event listener seems to prevent it from being GC'd.
public static void derived_destructor_really_frees()