forked from enlightenment/efl
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
This commit is contained in:
parent
1c22a3d819
commit
7c28762f15
|
@ -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,116 @@ 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())
|
||||
{
|
||||
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 = [®ular, &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 +248,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 +261,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 +282,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);
|
||||
|
||||
if (!(*etype).original_type.visit(unpack_event_args_visitor<decltype(arg_initializer_sink), Context>{arg_initializer_sink, &context, *etype}))
|
||||
auto sub_context = change_indentation(indent.inc().inc(), context);
|
||||
|
||||
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 +318,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 +344,10 @@ struct event_definition_generator
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!generate_event_add_remove(sink, evt, wrapper_evt_name, context))
|
||||
if (!generate_event_add_remove(sink, evt, event_args, context))
|
||||
return false;
|
||||
|
||||
if (!generate_event_trigger(sink, wrapper_evt_name, wrapper_args_type, wrapper_args_template, 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 +355,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 +383,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 +394,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"
|
||||
|
@ -365,13 +456,6 @@ struct is_eager_generator<struct ::eolian_mono::event_declaration_generator> : s
|
|||
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 <>
|
||||
|
@ -385,10 +469,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> {};
|
||||
|
|
|
@ -223,7 +223,6 @@ struct klass
|
|||
<< scope_tab << "private " << 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))
|
||||
|
@ -238,9 +237,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;
|
||||
|
@ -316,9 +312,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;
|
||||
|
@ -459,7 +452,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), (IntPtr evtCallerPtr, Efl.EventCb evtCaller)> eoEvents = new Dictionary<(IntPtr desc, object evtDelegate), (IntPtr evtCallerPtr, Efl.EventCb evtCaller)>();\n"
|
||||
<< scope_tab << visibility << "readonly object eventLock = new object();\n")
|
||||
.generate(sink, attributes::unused, context))
|
||||
return false;
|
||||
|
||||
if (is_inherit)
|
||||
|
@ -517,7 +512,6 @@ struct klass
|
|||
<< scope_tab << "protected " << 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;
|
||||
|
@ -560,7 +554,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 << scope_tab << "if (inherited)\n"
|
||||
<< scope_tab << scope_tab << "{\n"
|
||||
<< scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.PrivateDataSet(this);\n"
|
||||
|
@ -580,7 +573,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;
|
||||
|
||||
|
@ -588,92 +580,64 @@ 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 << "Monitor.Enter(Efl.Eo.Config.InitLock);\n"
|
||||
<< scope_tab << scope_tab << scope_tab << scope_tab << "if (Efl.Eo.Config.Initialized)\n"
|
||||
<< scope_tab << scope_tab << scope_tab << scope_tab << "{\n"
|
||||
<< scope_tab << 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 << scope_tab << "}\n\n"
|
||||
<< scope_tab << scope_tab << scope_tab << scope_tab << "Monitor.Exit(Efl.Eo.Config.InitLock);\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
|
||||
{
|
||||
|
@ -685,69 +649,70 @@ 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 << "///<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 << 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 << "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 << "IntPtr evtCallerPtr = Marshal.GetFunctionPointerForDelegate(evtCaller);\n"
|
||||
<< scope_tab << scope_tab << "if (!Efl.Eo.Globals.efl_event_callback_priority_add(handle, desc, 0, evtCallerPtr, 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)] = (evtCallerPtr, evtCaller);\n"
|
||||
<< scope_tab << scope_tab << "Eina.Error.RaiseIfUnhandledException();\n"
|
||||
<< scope_tab << "}\n\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 << "///<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 << "///<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 << 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 << "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 << 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 << scope_tab << "var evtPair = (desc, evtDelegate);\n"
|
||||
<< scope_tab << scope_tab << "if (eoEvents.TryGetValue(evtPair, out var caller))\n"
|
||||
<< scope_tab << scope_tab << "{\n"
|
||||
|
||||
<< scope_tab << scope_tab << scope_tab << "if (!Efl.Eo.Globals.efl_event_callback_del(handle, desc, caller.evtCallerPtr, 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))
|
||||
|
|
|
@ -134,6 +134,7 @@ run(options_type const& opts)
|
|||
"using System.Runtime.InteropServices;\n"
|
||||
"using System.Collections.Generic;\n"
|
||||
"using System.Linq;\n"
|
||||
"using System.Threading;\n"
|
||||
"using System.ComponentModel;\n")
|
||||
.generate(iterator, efl::eolian::grammar::attributes::unused, efl::eolian::grammar::context_null()))
|
||||
{
|
||||
|
|
|
@ -67,6 +67,12 @@ public class Globals
|
|||
efl_ref_count_delegate(IntPtr eo);
|
||||
[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);
|
||||
|
||||
|
@ -186,28 +192,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, IntPtr cb, IntPtr data);
|
||||
|
||||
[DllImport(efl.Libs.Eo)] [return: MarshalAs(UnmanagedType.U1)] public static extern bool
|
||||
efl_event_callback_del(IntPtr obj, IntPtr desc, IntPtr 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;
|
||||
|
||||
|
@ -625,17 +617,79 @@ public class Globals
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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), (IntPtr evtCallerPtr, Efl.EventCb evtCaller)>;
|
||||
if (eoEvents == null)
|
||||
{
|
||||
Eina.Log.Error($"Invalid event dictionary [GCHandle pointer: {gcHandlePtr}]");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in eoEvents)
|
||||
{
|
||||
if (!efl_event_callback_del(obj, item.Key.desc, item.Value.evtCallerPtr, IntPtr.Zero))
|
||||
{
|
||||
Eina.Log.Error($"Failed to remove event proxy for event {item.Key.desc} [cb: {item.Value.evtCallerPtr}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
|
||||
public static bool Initialized {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public static readonly object InitLock = new object();
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
Globals.efl_object_init();
|
||||
Monitor.Enter(InitLock);
|
||||
Initialized = true;
|
||||
Monitor.Exit(InitLock);
|
||||
Globals.SetNativeDisposeCallbacks();
|
||||
}
|
||||
|
||||
public static void Shutdown()
|
||||
{
|
||||
Monitor.Enter(InitLock);
|
||||
Initialized = false;
|
||||
Monitor.Exit(InitLock);
|
||||
Globals.efl_object_shutdown();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,6 +115,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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -49,6 +49,7 @@ class TestEo
|
|||
Test.Assert(delEventCalled, "DEL event not called");
|
||||
} */
|
||||
|
||||
/* Commented until we figure out a new way to test disposing
|
||||
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()
|
||||
|
|
Loading…
Reference in New Issue