forked from enlightenment/efl
Compare commits
7 Commits
master
...
devs/vitor
Author | SHA1 | Date |
---|---|---|
|
2b3b3b7704 | |
|
a902b56d98 | |
|
f6b9e2aa57 | |
|
fd01e096f7 | |
|
8538b00da6 | |
|
5d70b2c09f | |
|
97b56c9bcd |
|
@ -6,7 +6,9 @@ efl_eo_mono_files = \
|
|||
bindings/mono/eo_mono/iwrapper.cs \
|
||||
bindings/mono/eo_mono/FunctionWrapper.cs \
|
||||
bindings/mono/eo_mono/NativeModule.cs \
|
||||
bindings/mono/eo_mono/workaround.cs
|
||||
bindings/mono/eo_mono/workaround.cs \
|
||||
bindings/mono/eo_mono/EoWrapper.cs \
|
||||
bindings/mono/eo_mono/WrapperSupervisor.cs
|
||||
|
||||
if HAVE_WIN32
|
||||
|
||||
|
|
|
@ -38,10 +38,44 @@ bench_efl_add_jump_by_2(int request)
|
|||
free(objs);
|
||||
}
|
||||
|
||||
static void
|
||||
bench_efl_add_shared_ownership(int request)
|
||||
{
|
||||
int i;
|
||||
Eo **objs = calloc(request, sizeof(Eo *));
|
||||
Eo *p = efl_add_ref(SIMPLE_CLASS, NULL);
|
||||
for (i = 0; i < request; i++)
|
||||
objs[i] = efl_add_ref(SIMPLE_CLASS, p);
|
||||
efl_unref(p);
|
||||
for (i = 0; i < request; i++)
|
||||
efl_unref(objs[i]);
|
||||
free(objs);
|
||||
}
|
||||
|
||||
static void
|
||||
bench_efl_add_shared_ownership_alternative(int request)
|
||||
{
|
||||
int i;
|
||||
Eo **objs = calloc(request, sizeof(Eo *));
|
||||
Eo *p = efl_add_ref(SIMPLE_CLASS, NULL);
|
||||
for (i = 0; i < request; i++)
|
||||
objs[i] = efl_add(SIMPLE_CLASS, p);
|
||||
for (i = 0; i < request; i++)
|
||||
efl_ref(objs[i]);
|
||||
for (i = 0; i < request; i++)
|
||||
efl_unref(objs[i]);
|
||||
efl_unref(p);
|
||||
free(objs);
|
||||
}
|
||||
|
||||
void eo_bench_efl_add(Eina_Benchmark *bench)
|
||||
{
|
||||
eina_benchmark_register(bench, "efl_add_linear",
|
||||
EINA_BENCHMARK(bench_efl_add_linear), _EO_BENCH_TIMES(1000, 10, 50000));
|
||||
eina_benchmark_register(bench, "efl_add_jump_by_2",
|
||||
EINA_BENCHMARK(bench_efl_add_jump_by_2), _EO_BENCH_TIMES(1000, 10, 50000));
|
||||
eina_benchmark_register(bench, "efl_add_shared_ownership",
|
||||
EINA_BENCHMARK(bench_efl_add_shared_ownership), _EO_BENCH_TIMES(1000, 10, 50000));
|
||||
eina_benchmark_register(bench, "efl_add_shared_ownership_alternative",
|
||||
EINA_BENCHMARK(bench_efl_add_shared_ownership_alternative), _EO_BENCH_TIMES(1000, 10, 50000));
|
||||
}
|
||||
|
|
|
@ -431,10 +431,9 @@ struct event_definition_generator
|
|||
<< 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 << "var obj = Efl.Eo.Globals.WrapperSupervisorPtrToManaged(data).Target;\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
|
||||
|
|
|
@ -104,14 +104,14 @@ struct native_function_definition_generator
|
|||
<< ")\n"
|
||||
<< indent << "{\n"
|
||||
<< indent << scope_tab << "Eina.Log.Debug(\"function " << string << " was called\");\n"
|
||||
<< indent << scope_tab << "Efl.Eo.IWrapper wrapper = Efl.Eo.Globals.PrivateDataGet(pd);\n"
|
||||
<< indent << scope_tab << "if (wrapper != null)\n"
|
||||
<< indent << scope_tab << "var ws = Efl.Eo.Globals.GetWrapperSupervisor(obj);\n"
|
||||
<< indent << scope_tab << "if (ws != null)\n"
|
||||
<< indent << scope_tab << "{\n"
|
||||
<< eolian_mono::native_function_definition_preamble()
|
||||
<< indent << scope_tab << scope_tab << "try\n"
|
||||
<< indent << scope_tab << scope_tab << "{\n"
|
||||
<< indent << scope_tab << scope_tab << scope_tab << (return_type != "void" ? "_ret_var = " : "")
|
||||
<< (f.is_static ? "" : "((") << klass_cast_name << (f.is_static ? "." : ")wrapper).") << string
|
||||
<< (f.is_static ? "" : "((") << klass_cast_name << (f.is_static ? "." : ")ws.Target).") << string
|
||||
<< "(" << (native_argument_invocation % ", ") << ");\n"
|
||||
<< indent << scope_tab << scope_tab << "}\n"
|
||||
<< indent << scope_tab << scope_tab << "catch (Exception e)\n"
|
||||
|
|
|
@ -31,37 +31,6 @@
|
|||
|
||||
namespace eolian_mono {
|
||||
|
||||
template <typename OutputIterator, typename Context>
|
||||
static bool generate_equals_method(OutputIterator sink, Context const &context)
|
||||
{
|
||||
return as_generator(
|
||||
scope_tab << "/// <summary>Verifies if the given object is equal to this one.</summary>\n"
|
||||
<< scope_tab << "/// <param name=\"instance\">The object to compare to.</param>\n"
|
||||
<< scope_tab << "/// <returns>True if both objects point to the same native object.</returns>\n"
|
||||
<< scope_tab << "public override bool Equals(object instance)\n"
|
||||
<< scope_tab << "{\n"
|
||||
<< scope_tab << scope_tab << "var other = instance as Efl.Object;\n"
|
||||
<< scope_tab << scope_tab << "if (other == null)\n"
|
||||
<< scope_tab << scope_tab << "{\n"
|
||||
<< scope_tab << scope_tab << scope_tab << "return false;\n"
|
||||
<< scope_tab << scope_tab << "}\n"
|
||||
<< scope_tab << scope_tab << "return this.NativeHandle == other.NativeHandle;\n"
|
||||
<< scope_tab << "}\n\n"
|
||||
<< scope_tab << "/// <summary>Gets the hash code for this object based on the native pointer it points to.</summary>\n"
|
||||
<< scope_tab << "/// <returns>The value of the pointer, to be used as the hash code of this object.</returns>\n"
|
||||
<< scope_tab << "public override int GetHashCode()\n"
|
||||
<< scope_tab << "{\n"
|
||||
<< scope_tab << scope_tab << "return this.NativeHandle.ToInt32();\n"
|
||||
<< scope_tab << "}\n\n"
|
||||
<< scope_tab << "/// <summary>Turns the native pointer into a string representation.</summary>\n"
|
||||
<< scope_tab << "/// <returns>A string with the type and the native pointer for this object.</returns>\n"
|
||||
<< scope_tab << "public override String ToString()\n"
|
||||
<< scope_tab << "{\n"
|
||||
<< scope_tab << scope_tab << "return $\"{this.GetType().Name}@[{this.NativeHandle.ToInt32():x}]\";\n"
|
||||
<< scope_tab << "}\n\n"
|
||||
).generate(sink, nullptr, context);
|
||||
}
|
||||
|
||||
/* Get the actual number of functions of a class, checking for blacklisted ones */
|
||||
template<typename Context>
|
||||
static std::size_t
|
||||
|
@ -216,9 +185,9 @@ struct klass
|
|||
if(!as_generator
|
||||
(
|
||||
documentation
|
||||
<< "sealed public class " << concrete_name << " : " << "\n"
|
||||
<< (klass_full_concrete_or_interface_name % ",") << "\n"
|
||||
<< (inherit_classes.size() > 0 ? ", " : "" ) << interface_name << "\n"
|
||||
<< "sealed public class " << concrete_name << " :\n"
|
||||
<< scope_tab << (root ? "Efl.Eo.EoWrapper" : "") << (klass_full_concrete_or_interface_name % "") << "\n"
|
||||
<< scope_tab << ", " << interface_name << "\n"
|
||||
<< scope_tab << *(", " << name_helpers::klass_full_concrete_or_interface_name) << "\n"
|
||||
<< "{\n"
|
||||
).generate(sink, std::make_tuple(cls, inherit_classes, inherit_interfaces), concrete_cxt))
|
||||
|
@ -227,7 +196,6 @@ struct klass
|
|||
if (!generate_fields(sink, cls, concrete_cxt))
|
||||
return false;
|
||||
|
||||
bool root = !helpers::has_regular_ancestor(cls);
|
||||
if (!as_generator
|
||||
(
|
||||
scope_tab << "[System.Runtime.InteropServices.DllImport(" << context_find_tag<library_context>(concrete_cxt).actual_library_name(cls.filename)
|
||||
|
@ -235,20 +203,13 @@ struct klass
|
|||
<< scope_tab << scope_tab << name_helpers::klass_get_name(cls) << "();\n"
|
||||
<< scope_tab << "/// <summary>Initializes a new instance of the <see cref=\"" << interface_name << "\"/> class.\n"
|
||||
<< scope_tab << "/// Internal usage: This is used when interacting with C code and should not be used directly.</summary>\n"
|
||||
<< scope_tab << "private " << concrete_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
|
||||
<< scope_tab << "private " << concrete_name << "(System.IntPtr raw) : base(raw)\n"
|
||||
<< scope_tab << "{\n"
|
||||
<< scope_tab << scope_tab << (root ? "handle = raw;\n" : "")
|
||||
<< scope_tab << "}\n"
|
||||
<< scope_tab << "}\n\n"
|
||||
)
|
||||
.generate(sink, attributes::unused, concrete_cxt))
|
||||
return false;
|
||||
|
||||
if (!generate_dispose_methods(sink, cls, concrete_cxt))
|
||||
return false;
|
||||
|
||||
if (!generate_equals_method(sink, concrete_cxt))
|
||||
return false;
|
||||
|
||||
if (!generate_events(sink, cls, concrete_cxt))
|
||||
return false;
|
||||
|
||||
|
@ -305,10 +266,9 @@ struct klass
|
|||
<< "[" << name_helpers::klass_full_native_inherit_name(cls) << "]\n"
|
||||
<< "public " << class_type << " " << name_helpers::klass_concrete_name(cls) << " : "
|
||||
<< (klass_full_concrete_or_interface_name % ",") // classes
|
||||
<< (inherit_classes.empty() ? "" : ",")
|
||||
<< " Efl.Eo.IWrapper" << (root ? ", IDisposable" : "")
|
||||
<< (inherit_interfaces.empty() ? "" : ",")
|
||||
<< (klass_full_concrete_or_interface_name % ",") // interfaces
|
||||
<< (root ? "Efl.Eo.EoWrapper" : "") // ... or root
|
||||
<< (inherit_interfaces.empty() ? "" : ", ")
|
||||
<< (klass_full_concrete_or_interface_name % ", ") // interfaces
|
||||
<< "\n{\n"
|
||||
)
|
||||
.generate(sink, std::make_tuple(cls, inherit_classes, inherit_interfaces), inherit_cxt))
|
||||
|
@ -322,12 +282,6 @@ struct klass
|
|||
if (!generate_constructors(sink, cls, inherit_cxt))
|
||||
return false;
|
||||
|
||||
if (!generate_dispose_methods(sink, cls, inherit_cxt))
|
||||
return false;
|
||||
|
||||
if (!generate_equals_method(sink, inherit_cxt))
|
||||
return false;
|
||||
|
||||
if (!generate_events(sink, cls, inherit_cxt))
|
||||
return false;
|
||||
|
||||
|
@ -479,22 +433,14 @@ struct klass
|
|||
bool generate_fields(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const
|
||||
{
|
||||
std::string visibility = is_inherit_context(context) ? "protected " : "private ";
|
||||
bool root = !helpers::has_regular_ancestor(cls);
|
||||
bool is_inherit = is_inherit_context(context);
|
||||
|
||||
std::string class_getter = name_helpers::klass_get_name(cls) + "()";
|
||||
std::string native_inherit_full_name = name_helpers::klass_full_native_inherit_name(cls);
|
||||
auto inherit_name = name_helpers::klass_concrete_name(cls);
|
||||
|
||||
std::string raw_klass_modifier;
|
||||
if (!root)
|
||||
raw_klass_modifier = "override ";
|
||||
else if (is_inherit)
|
||||
raw_klass_modifier = "virtual ";
|
||||
|
||||
if(!as_generator(
|
||||
scope_tab << "///<summary>Pointer to the native class description.</summary>\n"
|
||||
<< scope_tab << "public " << raw_klass_modifier << "System.IntPtr NativeClass\n"
|
||||
<< scope_tab << "public override System.IntPtr NativeClass\n"
|
||||
<< scope_tab << "{\n"
|
||||
<< scope_tab << scope_tab << "get\n"
|
||||
<< scope_tab << scope_tab << "{\n"
|
||||
|
@ -511,42 +457,12 @@ struct klass
|
|||
).generate(sink, attributes::unused, context))
|
||||
return false;
|
||||
|
||||
// The remaining fields aren't needed in children classes.
|
||||
if (!root)
|
||||
return true;
|
||||
|
||||
if (cls.get_all_events().size() > 0)
|
||||
if (!as_generator(
|
||||
scope_tab << "/// <summary>Internal usage by derived classes to track native events.</summary>\n"
|
||||
<< 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 << "/// <summary>Internal usage by derived classes to lock native event handlers.</summary>\n"
|
||||
<< scope_tab << visibility << "readonly object eventLock = new object();\n")
|
||||
.generate(sink, attributes::unused, context))
|
||||
return false;
|
||||
|
||||
if (is_inherit)
|
||||
{
|
||||
if (!as_generator(
|
||||
scope_tab << "/// <summary>Internal usage to detect whether this instance is from a generated class or not.</summary>\n"
|
||||
<< scope_tab << "protected bool inherited;\n"
|
||||
).generate(sink, attributes::unused, context))
|
||||
return false;
|
||||
}
|
||||
|
||||
return as_generator(
|
||||
scope_tab << visibility << " System.IntPtr handle;\n"
|
||||
<< scope_tab << "///<summary>Pointer to the native instance.</summary>\n"
|
||||
<< scope_tab << "public System.IntPtr NativeHandle\n"
|
||||
<< scope_tab << "{\n"
|
||||
<< scope_tab << scope_tab << "get { return handle; }\n"
|
||||
<< scope_tab << "}\n\n"
|
||||
).generate(sink, attributes::unused, context);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename OutputIterator, typename Context>
|
||||
bool generate_constructors(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const
|
||||
{
|
||||
bool root = !helpers::has_regular_ancestor(cls);
|
||||
auto inherit_name = name_helpers::klass_concrete_name(cls);
|
||||
|
||||
if(!as_generator(
|
||||
|
@ -571,7 +487,7 @@ struct klass
|
|||
// For constructors with arguments, the parent is also required, as optional parameters can't come before non-optional paramenters.
|
||||
<< scope_tab << "public " << inherit_name << "(Efl.Object parent" << ((constructors.size() > 0) ? "" : "= null") << "\n"
|
||||
<< scope_tab << scope_tab << scope_tab << *(", " << constructor_param ) << ") : "
|
||||
<< (root ? "this" : "base") << "(" << name_helpers::klass_get_name(cls) << "(), typeof(" << inherit_name << "), parent)\n"
|
||||
<< "base(" << name_helpers::klass_get_name(cls) << "(), typeof(" << inherit_name << "), parent)\n"
|
||||
<< scope_tab << "{\n"
|
||||
<< (*(scope_tab << scope_tab << constructor_invocation << "\n"))
|
||||
<< scope_tab << scope_tab << "FinishInstantiation();\n"
|
||||
|
@ -579,9 +495,8 @@ struct klass
|
|||
<< scope_tab << "/// <summary>Initializes a new instance of the <see cref=\"" << inherit_name << "\"/> class.\n"
|
||||
<< scope_tab << "/// Internal usage: Constructs an instance from a native pointer. This is used when interacting with C code and should not be used directly.</summary>\n"
|
||||
<< scope_tab << "/// <param name=\"raw\">The native pointer to be wrapped.</param>\n"
|
||||
<< scope_tab << "protected " << inherit_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
|
||||
<< scope_tab << "protected " << inherit_name << "(System.IntPtr raw) : base(raw)\n"
|
||||
<< scope_tab << "{\n"
|
||||
<< scope_tab << scope_tab << (root ? "handle = raw;\n" : "")
|
||||
<< scope_tab << "}\n\n"
|
||||
).generate(sink, std::make_tuple(constructors, constructors, constructors), context))
|
||||
return false;
|
||||
|
@ -603,124 +518,16 @@ struct klass
|
|||
return false;
|
||||
}
|
||||
|
||||
// Internal constructors
|
||||
if (!root)
|
||||
{
|
||||
return as_generator(
|
||||
scope_tab << "/// <summary>Initializes a new instance of the <see cref=\"" << inherit_name << "\"/> class.\n"
|
||||
<< scope_tab << "/// Internal usage: Constructor to forward the wrapper initialization to the root class that interfaces with native code. Should not be used directly.</summary>\n"
|
||||
<< scope_tab << "/// <param name=\"baseKlass\">The pointer to the base native Eo class.</param>\n"
|
||||
<< scope_tab << "/// <param name=\"managedType\">The managed type of the public constructor that originated this call.</param>\n"
|
||||
<< scope_tab << "/// <param name=\"parent\">The Efl.Object parent of this instance.</param>\n"
|
||||
<< scope_tab << "protected " << inherit_name << "(IntPtr baseKlass, System.Type managedType, Efl.Object parent) : base(baseKlass, managedType, parent)\n"
|
||||
<< scope_tab << "{\n"
|
||||
<< scope_tab << "}\n\n"
|
||||
).generate(sink, attributes::unused, context);
|
||||
|
||||
}
|
||||
|
||||
// Detailed constructors go only in root classes.
|
||||
return as_generator(
|
||||
/// Actual root costructor that creates class and instantiates
|
||||
scope_tab << "/// <summary>Initializes a new instance of the <see cref=\"" << inherit_name << "\"/> class.\n"
|
||||
<< scope_tab << "/// Internal usage: Constructor to actually call the native library constructors. C# subclasses\n"
|
||||
<< scope_tab << "/// must use the public constructor only.</summary>\n"
|
||||
<< scope_tab << "/// <param name=\"baseKlass\">The pointer to the base native Eo class.</param>\n"
|
||||
<< scope_tab << "/// <param name=\"managedType\">The managed type of the public constructor that originated this call.</param>\n"
|
||||
<< scope_tab << "/// <param name=\"parent\">The Efl.Object parent of this instance.</param>\n"
|
||||
<< scope_tab << "protected " << inherit_name << "(IntPtr baseKlass, System.Type managedType, Efl.Object parent)\n"
|
||||
<< scope_tab << "{\n"
|
||||
<< scope_tab << scope_tab << "inherited = ((object)this).GetType() != managedType;\n"
|
||||
<< scope_tab << scope_tab << "IntPtr actual_klass = baseKlass;\n"
|
||||
<< scope_tab << scope_tab << "if (inherited)\n"
|
||||
<< scope_tab << scope_tab << "{\n"
|
||||
<< scope_tab << scope_tab << scope_tab << "actual_klass = Efl.Eo.ClassRegister.GetInheritKlassOrRegister(baseKlass, ((object)this).GetType());\n"
|
||||
<< scope_tab << scope_tab << "}\n\n"
|
||||
<< scope_tab << scope_tab << "handle = Efl.Eo.Globals.instantiate_start(actual_klass, parent);\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"
|
||||
<< scope_tab << scope_tab << "}\n"
|
||||
<< scope_tab << "}\n\n"
|
||||
|
||||
<< scope_tab << "/// <summary>Finishes instantiating this object.\n"
|
||||
<< scope_tab << "/// Internal usage by generated code.</summary>\n"
|
||||
<< scope_tab << "protected void FinishInstantiation()\n"
|
||||
<< scope_tab << "{\n"
|
||||
<< scope_tab << scope_tab << "handle = Efl.Eo.Globals.instantiate_end(handle);\n"
|
||||
<< scope_tab << scope_tab << "Eina.Error.RaiseIfUnhandledException();\n"
|
||||
<< scope_tab << "}\n\n"
|
||||
|
||||
).generate(sink, attributes::unused, context);
|
||||
}
|
||||
|
||||
|
||||
template <typename OutputIterator, typename Context>
|
||||
bool generate_dispose_methods(OutputIterator sink, attributes::klass_def const& cls, Context const& context) const
|
||||
{
|
||||
if (helpers::has_regular_ancestor(cls))
|
||||
return true;
|
||||
|
||||
std::string visibility = is_inherit_context(context) ? "protected virtual " : "private ";
|
||||
|
||||
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\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 << "{\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_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 << "Monitor.Enter(Efl.All.InitLock);\n"
|
||||
<< scope_tab << scope_tab << scope_tab << scope_tab << "if (Efl.All.MainLoopInitialized)\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.All.InitLock);\n"
|
||||
<< scope_tab << scope_tab << scope_tab << "}\n"
|
||||
<< scope_tab << scope_tab << "}\n\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\n"
|
||||
).generate(sink, attributes::unused, context);
|
||||
scope_tab << "/// <summary>Initializes a new instance of the <see cref=\"" << inherit_name << "\"/> class.\n"
|
||||
<< scope_tab << "/// Internal usage: Constructor to forward the wrapper initialization to the root class that interfaces with native code. Should not be used directly.</summary>\n"
|
||||
<< scope_tab << "/// <param name=\"baseKlass\">The pointer to the base native Eo class.</param>\n"
|
||||
<< scope_tab << "/// <param name=\"managedType\">The managed type of the public constructor that originated this call.</param>\n"
|
||||
<< scope_tab << "/// <param name=\"parent\">The Efl.Object parent of this instance.</param>\n"
|
||||
<< scope_tab << "protected " << inherit_name << "(IntPtr baseKlass, System.Type managedType, Efl.Object parent) : base(baseKlass, managedType, parent)\n"
|
||||
<< scope_tab << "{\n"
|
||||
<< scope_tab << "}\n\n"
|
||||
).generate(sink, attributes::unused, context);
|
||||
}
|
||||
|
||||
template <typename OutputIterator, typename Context>
|
||||
|
@ -730,80 +537,6 @@ struct klass
|
|||
if (!has_events(cls))
|
||||
return true;
|
||||
|
||||
std::string visibility = is_inherit_context(context) ? "protected " : "private ";
|
||||
|
||||
if (!helpers::has_regular_ancestor(cls))
|
||||
{
|
||||
// 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=\"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 << "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 << "///<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=\"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 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;\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 << "}\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\n"
|
||||
)
|
||||
.generate(sink, NULL, context))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Self events
|
||||
if (!as_generator(*(event_definition(cls, cls))).generate(sink, cls.events, context))
|
||||
return false;
|
||||
|
|
|
@ -72,8 +72,12 @@ public static class All
|
|||
{
|
||||
// Try to cleanup everything before actually shutting down.
|
||||
Eina.Log.Debug("Calling GC before shutdown");
|
||||
System.GC.Collect();
|
||||
System.GC.WaitForPendingFinalizers();
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
System.GC.Collect();
|
||||
System.GC.WaitForPendingFinalizers();
|
||||
Efl.App.AppMain.Iterate();
|
||||
}
|
||||
|
||||
Monitor.Enter(InitLock);
|
||||
MainLoopInitialized = false;
|
||||
|
|
|
@ -229,7 +229,7 @@ public class EflObjectElementTraits<T> : IBaseElementTraits<T>
|
|||
{
|
||||
if (nat != IntPtr.Zero)
|
||||
{
|
||||
Efl.Eo.Globals.efl_mono_thread_safe_efl_unref(nat);
|
||||
Efl.Eo.Globals.efl_mono_thread_safe_efl_unref(nat);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,304 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Efl
|
||||
{
|
||||
|
||||
namespace Eo
|
||||
{
|
||||
|
||||
#if EFL_DEBUG
|
||||
|
||||
public class SafeIntPtr
|
||||
{
|
||||
private IntPtr handle;
|
||||
private bool disposed;
|
||||
|
||||
private SafeIntPtr(IntPtr ptr)
|
||||
{
|
||||
handle = ptr;
|
||||
}
|
||||
|
||||
public static implicit operator IntPtr(SafeIntPtr ptr)
|
||||
{
|
||||
if (ptr.disposed)
|
||||
{
|
||||
throw new ObjectDisposedException("Object has been disposed");
|
||||
}
|
||||
return ptr.handle;
|
||||
}
|
||||
|
||||
public static implicit operator SafeIntPtr(IntPtr ptr)
|
||||
{
|
||||
return new SafeIntPtr(ptr);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
disposed = true;
|
||||
handle = IntPtr.Zero;
|
||||
}
|
||||
|
||||
public long ToInt64()
|
||||
{
|
||||
return handle.ToInt64();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public abstract class EoWrapper : IWrapper, IDisposable
|
||||
{
|
||||
protected readonly object eventLock = new object();
|
||||
protected bool inherited = false;
|
||||
#if EFL_DEBUG
|
||||
protected SafeIntPtr handle;
|
||||
#else
|
||||
protected IntPtr handle;
|
||||
#endif
|
||||
|
||||
private static Efl.EventCb ownershipUniqueDelegate = new Efl.EventCb(OwnershipUniqueCallback);
|
||||
private static Efl.EventCb ownershipSharedDelegate = new Efl.EventCb(OwnershipSharedCallback);
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="Object"/> class.
|
||||
/// Internal usage: Constructs an instance from a native pointer. This is used when interacting with C code and should not be used directly.</summary>
|
||||
/// <param name="raw">The native pointer to be wrapped.</param>
|
||||
protected EoWrapper(System.IntPtr raw)
|
||||
{
|
||||
handle = raw;
|
||||
AddWrapperSupervisor();
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="Object"/> class.
|
||||
/// Internal usage: Constructor to actually call the native library constructors. C# subclasses
|
||||
/// must use the public constructor only.</summary>
|
||||
/// <param name="baseKlass">The pointer to the base native Eo class.</param>
|
||||
/// <param name="managedType">The managed type of the public constructor that originated this call.</param>
|
||||
/// <param name="parent">The Efl.Object parent of this instance.</param>
|
||||
/// <param name="file">Name of the file from where the constructor is called.</param>
|
||||
/// <param name="line">Number of the line from where the constructor is called.</param>
|
||||
protected EoWrapper(IntPtr baseKlass, System.Type managedType, Efl.Object parent,
|
||||
[CallerFilePath] string file = null,
|
||||
[CallerLineNumber] int line = 0)
|
||||
{
|
||||
inherited = ((object)this).GetType() != managedType;
|
||||
IntPtr actual_klass = baseKlass;
|
||||
if (inherited)
|
||||
{
|
||||
actual_klass = Efl.Eo.ClassRegister.GetInheritKlassOrRegister(baseKlass, ((object)this).GetType());
|
||||
}
|
||||
|
||||
// Creation of the unfinalized Eo handle
|
||||
Eina.Log.Debug($"Instantiating from klass 0x{actual_klass.ToInt64():x}");
|
||||
System.IntPtr parent_ptr = System.IntPtr.Zero;
|
||||
if (parent != null)
|
||||
{
|
||||
parent_ptr = parent.NativeHandle;
|
||||
}
|
||||
|
||||
handle = Efl.Eo.Globals._efl_add_internal_start(file, line, actual_klass, parent_ptr, 1, 0);
|
||||
if (handle == System.IntPtr.Zero)
|
||||
{
|
||||
throw new Exception("Instantiation failed");
|
||||
}
|
||||
|
||||
Eina.Log.Debug($"Eo instance right after internal_start 0x{handle.ToInt64():x} with refcount {Efl.Eo.Globals.efl_ref_count(handle)}");
|
||||
Eina.Log.Debug($"Parent was 0x{parent_ptr.ToInt64()}");
|
||||
|
||||
// Creation of wrapper supervisor
|
||||
AddWrapperSupervisor();
|
||||
}
|
||||
|
||||
/// <summary>Destructor.</summary>
|
||||
~EoWrapper()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>Pointer to the native instance.</summary>
|
||||
public System.IntPtr NativeHandle
|
||||
{
|
||||
get { return handle; }
|
||||
}
|
||||
|
||||
/// <summary>Pointer to the native class description.</summary>
|
||||
public abstract System.IntPtr NativeClass
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>Releases the underlying native instance.</summary>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && handle != System.IntPtr.Zero)
|
||||
{
|
||||
IntPtr h = handle;
|
||||
#if EFL_DEBUG
|
||||
handle.Dispose();
|
||||
#else
|
||||
handle = IntPtr.Zero;
|
||||
#endif
|
||||
Efl.Eo.Globals.efl_mono_native_dispose(h);
|
||||
}
|
||||
else
|
||||
{
|
||||
Monitor.Enter(Efl.All.InitLock);
|
||||
if (Efl.All.MainLoopInitialized)
|
||||
{
|
||||
Efl.Eo.Globals.efl_mono_thread_safe_native_dispose(handle);
|
||||
}
|
||||
|
||||
Monitor.Exit(Efl.All.InitLock);
|
||||
#if EFL_DEBUG
|
||||
handle.Dispose();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Turns the native pointer into a string representation.</summary>
|
||||
/// <returns>A string with the type and the native pointer for this object.</returns>
|
||||
public override String ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}@[0x{handle.ToInt64():x}]";
|
||||
}
|
||||
|
||||
/// <summary>Releases the underlying native instance.</summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>Releases the underlying Eo object.
|
||||
///
|
||||
/// This method is a C# counterpart to the C `efl_del` function. It removes the parent of the object
|
||||
/// and releases the Eo reference it was holding.
|
||||
/// </summary>
|
||||
public void Del()
|
||||
{
|
||||
// FIXME Implement this
|
||||
((Efl.Object)this).SetParent(null);
|
||||
Dispose();
|
||||
}
|
||||
|
||||
/// <summary>Finishes instantiating this object.
|
||||
/// Internal usage by generated code.</summary>
|
||||
protected void FinishInstantiation()
|
||||
{
|
||||
Eina.Log.Debug("calling efl_add_internal_end");
|
||||
var h = Efl.Eo.Globals._efl_add_end(handle, 1, 0);
|
||||
Eina.Log.Debug($"efl_add_end returned eo 0x{handle.ToInt64():x}");
|
||||
|
||||
// if (h == IntPtr.Zero) // TODO
|
||||
// {
|
||||
// }
|
||||
|
||||
handle = h;
|
||||
}
|
||||
|
||||
/// <summary>Adds a new event handler, registering it to the native event. For internal use only.</summary>
|
||||
/// <param name="lib">The name of the native library definining the event.</param>
|
||||
/// <param name="key">The name of the native event.</param>
|
||||
/// <param name="evtCaller">Delegate to be called by native code on event raising.</param>
|
||||
/// <param name="evtDelegate">Managed delegate that will be called by evtCaller on event raising.</param>
|
||||
protected void AddNativeEventHandler(string lib, string key, Efl.EventCb evtCaller, object evtDelegate)
|
||||
{
|
||||
IntPtr desc = Efl.EventDescription.GetNative(lib, key);
|
||||
if (desc == IntPtr.Zero)
|
||||
{
|
||||
Eina.Log.Error($"Failed to get native event {key}");
|
||||
return;
|
||||
}
|
||||
|
||||
var wsPtr = Efl.Eo.Globals.efl_mono_wrapper_supervisor_get(handle);
|
||||
var ws = Efl.Eo.Globals.WrapperSupervisorPtrToManaged(wsPtr);
|
||||
if (ws.EoEvents.ContainsKey((desc, evtDelegate)))
|
||||
{
|
||||
Eina.Log.Warning($"Event proxy for event {key} already registered!");
|
||||
return;
|
||||
}
|
||||
|
||||
IntPtr evtCallerPtr = Marshal.GetFunctionPointerForDelegate(evtCaller);
|
||||
if (!Efl.Eo.Globals.efl_event_callback_priority_add(handle, desc, 0, evtCallerPtr, wsPtr))
|
||||
{
|
||||
Eina.Log.Error($"Failed to add event proxy for event {key}");
|
||||
return;
|
||||
}
|
||||
|
||||
ws.EoEvents[(desc, evtDelegate)] = (evtCallerPtr, evtCaller);
|
||||
Eina.Error.RaiseIfUnhandledException();
|
||||
}
|
||||
|
||||
/// <summary>Removes the given event handler for the given event. For internal use only.</summary>
|
||||
/// <param name="lib">The name of the native library definining the event.</param>
|
||||
/// <param name="key">The name of the native event.</param>
|
||||
/// <param name="evtDelegate">The delegate to be removed.</param>
|
||||
protected void RemoveNativeEventHandler(string lib, string key, object evtDelegate)
|
||||
{
|
||||
IntPtr desc = Efl.EventDescription.GetNative(lib, key);
|
||||
if (desc == IntPtr.Zero)
|
||||
{
|
||||
Eina.Log.Error($"Failed to get native event {key}");
|
||||
return;
|
||||
}
|
||||
|
||||
var wsPtr = Efl.Eo.Globals.efl_mono_wrapper_supervisor_get(handle);
|
||||
var ws = Efl.Eo.Globals.WrapperSupervisorPtrToManaged(wsPtr);
|
||||
var evtPair = (desc, evtDelegate);
|
||||
if (ws.EoEvents.TryGetValue(evtPair, out var caller))
|
||||
{
|
||||
if (!Efl.Eo.Globals.efl_event_callback_del(handle, desc, caller.evtCallerPtr, wsPtr))
|
||||
{
|
||||
Eina.Log.Error($"Failed to remove event proxy for event {key}");
|
||||
return;
|
||||
}
|
||||
|
||||
ws.EoEvents.Remove(evtPair);
|
||||
Eina.Error.RaiseIfUnhandledException();
|
||||
}
|
||||
else
|
||||
{
|
||||
Eina.Log.Error($"Trying to remove proxy for event {key} when it is not registered.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void OwnershipUniqueCallback(IntPtr data, ref Efl.Event.NativeStruct evt)
|
||||
{
|
||||
var ws = Efl.Eo.Globals.WrapperSupervisorPtrToManaged(data);
|
||||
ws.MakeUnique();
|
||||
}
|
||||
|
||||
private static void OwnershipSharedCallback(IntPtr data, ref Efl.Event.NativeStruct evt)
|
||||
{
|
||||
var ws = Efl.Eo.Globals.WrapperSupervisorPtrToManaged(data);
|
||||
ws.MakeShared();
|
||||
}
|
||||
|
||||
/// <sumary>Create and set to the internal native state a C# supervisor for this Eo wrapper. For internal use only.</sumary>
|
||||
private void AddWrapperSupervisor()
|
||||
{
|
||||
var ws = new Efl.Eo.WrapperSupervisor(this);
|
||||
Efl.Eo.Globals.SetWrapperSupervisor(handle, ws);
|
||||
if (Efl.Eo.Globals.efl_ref_count(handle) > 1)
|
||||
{
|
||||
ws.MakeShared();
|
||||
}
|
||||
|
||||
AddOwnershipEventHandlers();
|
||||
}
|
||||
|
||||
/// <summary>Register handlers to ownership events, in order to control the object lifetime. For internal use only.</summary>
|
||||
private void AddOwnershipEventHandlers()
|
||||
{
|
||||
AddNativeEventHandler("eo", "_EFL_EVENT_INVALIDATE", ownershipUniqueDelegate, ownershipUniqueDelegate);
|
||||
AddNativeEventHandler("eo", "_EFL_EVENT_OWNERSHIP_UNIQUE", ownershipUniqueDelegate, ownershipUniqueDelegate);
|
||||
AddNativeEventHandler("eo", "_EFL_EVENT_OWNERSHIP_SHARED", ownershipSharedDelegate, ownershipSharedDelegate);
|
||||
Eina.Error.RaiseIfUnhandledException();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Global
|
||||
|
||||
} // namespace Efl
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using EventDictionary = System.Collections.Generic.Dictionary<(System.IntPtr desc, object evtDelegate), (System.IntPtr evtCallerPtr, Efl.EventCb evtCaller)>;
|
||||
|
||||
namespace Efl
|
||||
{
|
||||
|
||||
namespace Eo
|
||||
{
|
||||
|
||||
/// <summary>Observe the ownership state of an Eo wrapper and control its life-cycle.</summary>
|
||||
public class WrapperSupervisor
|
||||
{
|
||||
private System.WeakReference weakRef;
|
||||
#pragma warning disable CS0414
|
||||
private Efl.Eo.IWrapper sharedRef;
|
||||
#pragma warning restore CS0414
|
||||
private EventDictionary eoEvents;
|
||||
|
||||
/// <summary>Create a new supervisor for the given.</summary>
|
||||
/// <param name="obj">Efl object to be supervised.</param>
|
||||
public WrapperSupervisor(Efl.Eo.IWrapper obj)
|
||||
{
|
||||
weakRef = new WeakReference(obj);
|
||||
sharedRef = null;
|
||||
eoEvents = new EventDictionary();
|
||||
}
|
||||
|
||||
/// <summary>Efl object being supervised.</summary>
|
||||
public Efl.Eo.IWrapper Target
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Efl.Eo.IWrapper) weakRef.Target;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Dictionary that holds the events related with the supervised object.</summary>
|
||||
public EventDictionary EoEvents
|
||||
{
|
||||
get
|
||||
{
|
||||
return eoEvents;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>To be called when the object is uniquely owned by C#, removing its strong reference and making it available to garbage collection.</summary>
|
||||
public void MakeUnique()
|
||||
{
|
||||
sharedRef = null;
|
||||
}
|
||||
|
||||
/// <summary>To be called when the object is owned in the native library too, adding a strong reference to it and making it unavailable for garbage collection.</summary>
|
||||
public void MakeShared()
|
||||
{
|
||||
if (this.Target == null)
|
||||
throw new InvalidOperationException("Tried to make a null reference shared.");
|
||||
sharedRef = this.Target;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -48,6 +48,10 @@ public class Globals
|
|||
public delegate IntPtr
|
||||
_efl_add_internal_start_delegate([MarshalAs(UnmanagedType.LPStr)] String file, int line,
|
||||
IntPtr klass, IntPtr parent, byte is_ref, byte is_fallback);
|
||||
|
||||
[DllImport(efl.Libs.CustomExports)] public static extern IntPtr efl_mono_wrapper_supervisor_get(IntPtr eo);
|
||||
[DllImport(efl.Libs.CustomExports)] public static extern void efl_mono_wrapper_supervisor_set(IntPtr eo, IntPtr ws);
|
||||
|
||||
[DllImport(efl.Libs.Eo)] public static extern IntPtr
|
||||
_efl_add_internal_start([MarshalAs(UnmanagedType.LPStr)] String file, int line,
|
||||
IntPtr klass, IntPtr parent, byte is_ref, byte is_fallback);
|
||||
|
@ -68,11 +72,11 @@ 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);
|
||||
efl_mono_wrapper_supervisor_callbacks_set(Efl.FreeWrapperSupervisorCb freeWrapperSupervisorCb);
|
||||
[DllImport(efl.Libs.CustomExports)] public static extern void
|
||||
efl_mono_native_dispose(IntPtr eo, IntPtr gcHandle);
|
||||
efl_mono_native_dispose(IntPtr eo);
|
||||
[DllImport(efl.Libs.CustomExports)] public static extern void
|
||||
efl_mono_thread_safe_native_dispose(IntPtr eo, IntPtr gcHandle);
|
||||
efl_mono_thread_safe_native_dispose(IntPtr eo);
|
||||
[DllImport(efl.Libs.CustomExports)] public static extern void
|
||||
efl_mono_thread_safe_efl_unref(IntPtr eo);
|
||||
|
||||
|
@ -231,7 +235,7 @@ public class Globals
|
|||
description.version = 2; // EO_VERSION
|
||||
description.name = class_name;
|
||||
description.class_type = 0; // REGULAR
|
||||
description.data_size = (UIntPtr)8;
|
||||
description.data_size = (UIntPtr)0;
|
||||
description.class_initializer = IntPtr.Zero;
|
||||
description.class_constructor = IntPtr.Zero;
|
||||
description.class_destructor = IntPtr.Zero;
|
||||
|
@ -246,6 +250,8 @@ public class Globals
|
|||
IntPtr description_ptr = Eina.MemoryNative.Alloc(Marshal.SizeOf(description));
|
||||
Marshal.StructureToPtr(description, description_ptr, false);
|
||||
|
||||
// FIXME: description_ptr seems to be leaking memory even after an eo_shutdown
|
||||
|
||||
var interface_list = EoG.get_efl_interfaces(type);
|
||||
|
||||
Eina.Log.Debug($"Going to register new class named {class_name}");
|
||||
|
@ -442,60 +448,26 @@ public class Globals
|
|||
}
|
||||
}
|
||||
|
||||
public static IntPtr instantiate_start(IntPtr klass, Efl.Object parent,
|
||||
[CallerFilePath] string file = null,
|
||||
[CallerLineNumber] int line = 0)
|
||||
public static Efl.Eo.WrapperSupervisor WrapperSupervisorPtrToManaged(IntPtr wsPtr)
|
||||
{
|
||||
Eina.Log.Debug($"Instantiating from klass 0x{klass.ToInt64():x}");
|
||||
System.IntPtr parent_ptr = System.IntPtr.Zero;
|
||||
if (parent != null)
|
||||
{
|
||||
parent_ptr = parent.NativeHandle;
|
||||
}
|
||||
|
||||
System.IntPtr eo = Efl.Eo.Globals._efl_add_internal_start(file, line, klass, parent_ptr, 1, 0);
|
||||
if (eo == System.IntPtr.Zero)
|
||||
{
|
||||
throw new Exception("Instantiation failed");
|
||||
}
|
||||
|
||||
Eina.Log.Debug($"Eo instance right after internal_start 0x{eo.ToInt64():x} with refcount {Efl.Eo.Globals.efl_ref_count(eo)}");
|
||||
Eina.Log.Debug($"Parent was 0x{parent_ptr.ToInt64()}");
|
||||
return eo;
|
||||
return (Efl.Eo.WrapperSupervisor) GCHandle.FromIntPtr(wsPtr).Target;
|
||||
}
|
||||
|
||||
public static IntPtr instantiate_end(IntPtr eo)
|
||||
public static Efl.Eo.WrapperSupervisor GetWrapperSupervisor(IntPtr eo)
|
||||
{
|
||||
Eina.Log.Debug("calling efl_add_internal_end");
|
||||
eo = Efl.Eo.Globals._efl_add_end(eo, 1, 0);
|
||||
Eina.Log.Debug($"efl_add_end returned eo 0x{eo.ToInt64():x}");
|
||||
return eo;
|
||||
}
|
||||
|
||||
public static void PrivateDataSet(Efl.Eo.IWrapper obj)
|
||||
{
|
||||
Eina.Log.Debug($"Calling data_scope_get with obj {obj.NativeHandle.ToInt64():x} and klass {obj.NativeClass.ToInt64():x}");
|
||||
IntPtr pd = Efl.Eo.Globals.efl_data_scope_get(obj.NativeHandle, obj.NativeClass);
|
||||
{
|
||||
GCHandle gch = GCHandle.Alloc(obj);
|
||||
EolianPD epd;
|
||||
epd.pointer = GCHandle.ToIntPtr(gch);
|
||||
Marshal.StructureToPtr(epd, pd, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static Efl.Eo.IWrapper PrivateDataGet(IntPtr pd)
|
||||
{
|
||||
EolianPD epd = (EolianPD)Marshal.PtrToStructure(pd, typeof(EolianPD));
|
||||
if (epd.pointer != IntPtr.Zero)
|
||||
{
|
||||
GCHandle gch = GCHandle.FromIntPtr(epd.pointer);
|
||||
return (Efl.Eo.IWrapper)gch.Target;
|
||||
}
|
||||
else
|
||||
var wsPtr = Efl.Eo.Globals.efl_mono_wrapper_supervisor_get(eo);
|
||||
if (wsPtr == IntPtr.Zero)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return WrapperSupervisorPtrToManaged(wsPtr);
|
||||
}
|
||||
|
||||
public static void SetWrapperSupervisor(IntPtr eo, Efl.Eo.WrapperSupervisor ws)
|
||||
{
|
||||
GCHandle gch = GCHandle.Alloc(ws);
|
||||
Efl.Eo.Globals.efl_mono_wrapper_supervisor_set(eo, GCHandle.ToIntPtr(gch));
|
||||
}
|
||||
|
||||
public static void free_dict_values(Dictionary<String, IntPtr> dict)
|
||||
|
@ -601,93 +573,101 @@ public class Globals
|
|||
return null;
|
||||
}
|
||||
|
||||
IntPtr eoKlass = efl_class_get(handle);
|
||||
|
||||
if (eoKlass == IntPtr.Zero)
|
||||
Efl.Eo.Globals.efl_ref(handle);
|
||||
try
|
||||
{
|
||||
throw new InvalidOperationException($"Can't get Eo class for object handle 0x{handle.ToInt64():x}");
|
||||
}
|
||||
|
||||
var managedType = ClassRegister.GetManagedType(eoKlass);
|
||||
|
||||
if (managedType == null)
|
||||
{
|
||||
IntPtr nativeName = efl_class_name_get(eoKlass);
|
||||
var name = Eina.StringConversion.NativeUtf8ToManagedString(nativeName);
|
||||
|
||||
throw new InvalidOperationException($"Can't get Managed class for object handle 0x{handle.ToInt64():x} with native class [{name}]");
|
||||
}
|
||||
|
||||
// Pure C# classes that inherit from generated classes store their C# instance in their
|
||||
// Eo private data field.
|
||||
if (!IsGeneratedClass(managedType))
|
||||
{
|
||||
Efl.Eo.IWrapper instance = null;
|
||||
IntPtr pd = efl_data_scope_get(handle, eoKlass);
|
||||
|
||||
if (pd != IntPtr.Zero)
|
||||
var ws = Efl.Eo.Globals.GetWrapperSupervisor(handle);
|
||||
if (ws != null && ws.Target != null)
|
||||
{
|
||||
instance = PrivateDataGet(pd);
|
||||
if (!shouldIncRef)
|
||||
{
|
||||
Efl.Eo.Globals.efl_unref(handle);
|
||||
}
|
||||
|
||||
return ws.Target;
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
IntPtr eoKlass = efl_class_get(handle);
|
||||
|
||||
System.Reflection.ConstructorInfo constructor = null;
|
||||
|
||||
try
|
||||
{
|
||||
var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
constructor = managedType.GetConstructor(flags, null, new Type[1] { typeof(System.IntPtr) }, null);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
throw new InvalidOperationException($"Can't get constructor for type {managedType}");
|
||||
}
|
||||
|
||||
var ret = constructor.Invoke(new object[1] { handle }) as Efl.Eo.IWrapper;
|
||||
|
||||
if (ret != null && shouldIncRef)
|
||||
Efl.Eo.Globals.efl_ref(handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static Efl.FreeGCHandleCb FreeGCHandleCallbackDelegate = new Efl.FreeGCHandleCb(FreeGCHandleCallback);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private static Efl.RemoveEventsCb RemoveEventsCallbackDelegate = new Efl.RemoveEventsCb(RemoveEventsCallback);
|
||||
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)
|
||||
if (eoKlass == IntPtr.Zero)
|
||||
{
|
||||
Eina.Log.Error($"Invalid event dictionary [GCHandle pointer: {gcHandlePtr}]");
|
||||
throw new InvalidOperationException($"Can't get Eo class for object handle 0x{handle.ToInt64():x}");
|
||||
}
|
||||
|
||||
var managedType = ClassRegister.GetManagedType(eoKlass);
|
||||
|
||||
if (managedType == null)
|
||||
{
|
||||
IntPtr nativeName = efl_class_name_get(eoKlass);
|
||||
var name = Eina.StringConversion.NativeUtf8ToManagedString(nativeName);
|
||||
|
||||
throw new InvalidOperationException($"Can't get Managed class for object handle 0x{handle.ToInt64():x} with native class [{name}]");
|
||||
}
|
||||
|
||||
Debug.Assert(IsGeneratedClass(managedType));
|
||||
System.Reflection.ConstructorInfo constructor = null;
|
||||
|
||||
try
|
||||
{
|
||||
var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
constructor = managedType.GetConstructor(flags, null, new Type[1] { typeof(System.IntPtr) }, null);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
throw new InvalidOperationException($"Can't get constructor for type {managedType}");
|
||||
}
|
||||
|
||||
var ret = (Efl.Eo.IWrapper) constructor.Invoke(new object[1] { handle });
|
||||
|
||||
if (ret == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Can't construct type {managedType} from IntPtr handle");
|
||||
}
|
||||
|
||||
if (shouldIncRef)
|
||||
{
|
||||
Efl.Eo.Globals.efl_ref(handle);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Efl.Eo.Globals.efl_unref(handle);
|
||||
}
|
||||
}
|
||||
|
||||
private static Efl.FreeWrapperSupervisorCb FreeWrapperSupervisorCallbackDelegate = new Efl.FreeWrapperSupervisorCb(FreeWrapperSupervisorCallback);
|
||||
public static void FreeWrapperSupervisorCallback(IntPtr eo)
|
||||
{
|
||||
try
|
||||
{
|
||||
var wsPtr = Efl.Eo.Globals.efl_mono_wrapper_supervisor_get(eo);
|
||||
if (wsPtr == IntPtr.Zero)
|
||||
{
|
||||
Eina.Log.Error($"Invalid wrapper supervisor [Eo pointer: {eo.ToInt64():x}]");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in eoEvents)
|
||||
Efl.Eo.Globals.efl_mono_wrapper_supervisor_set(eo, IntPtr.Zero);
|
||||
|
||||
GCHandle gch = GCHandle.FromIntPtr(wsPtr);
|
||||
var ws = (Efl.Eo.WrapperSupervisor) gch.Target;
|
||||
foreach (var item in ws.EoEvents)
|
||||
{
|
||||
if (!efl_event_callback_del(obj, item.Key.desc, item.Value.evtCallerPtr, IntPtr.Zero))
|
||||
if (!efl_event_callback_del(eo, item.Key.desc, item.Value.evtCallerPtr, wsPtr))
|
||||
{
|
||||
Eina.Log.Error($"Failed to remove event proxy for event {item.Key.desc} [cb: {item.Value.evtCallerPtr}]");
|
||||
Eina.Log.Error($"Failed to remove event proxy for event {item.Key.desc} [eo: {eo.ToInt64():x}; cb: {item.Value.evtCallerPtr.ToInt64():x}]");
|
||||
}
|
||||
}
|
||||
|
||||
// Free the native eo
|
||||
Efl.Eo.Globals.efl_unref(eo);
|
||||
|
||||
// now the WrapperSupervisor can be collected, and so its member:
|
||||
// - the event dictionary
|
||||
// - and the EoWrapper if it is still pinned
|
||||
gch.Free();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -698,7 +678,7 @@ public class Globals
|
|||
|
||||
public static void SetNativeDisposeCallbacks()
|
||||
{
|
||||
efl_mono_gchandle_callbacks_set(FreeGCHandleCallbackDelegate, RemoveEventsCallbackDelegate);
|
||||
efl_mono_wrapper_supervisor_callbacks_set(FreeWrapperSupervisorCallbackDelegate);
|
||||
}
|
||||
|
||||
public static void ThreadSafeFreeCbExec(EinaFreeCb cbFreeCb, IntPtr cbData)
|
||||
|
@ -800,8 +780,6 @@ public static class ClassRegister
|
|||
string name = Eina.StringConversion.NativeUtf8ToManagedString(namePtr)
|
||||
.Replace("_", ""); // Convert Efl C name to C# name
|
||||
|
||||
var klass_type = Efl.Eo.Globals.efl_class_type_get(klass);
|
||||
|
||||
// Check if this is an internal implementation of an abstract class
|
||||
var abstract_impl_suffix = "Realized";
|
||||
if (name.EndsWith(abstract_impl_suffix))
|
||||
|
@ -813,6 +791,7 @@ public static class ClassRegister
|
|||
}
|
||||
|
||||
// When converting to managed, interfaces and mixins gets the 'I' prefix.
|
||||
var klass_type = Efl.Eo.Globals.efl_class_type_get(klass);
|
||||
if (klass_type == Efl.Eo.Globals.EflClassType.Interface || klass_type == Efl.Eo.Globals.EflClassType.Mixin)
|
||||
{
|
||||
var pos = name.LastIndexOf(".");
|
||||
|
|
|
@ -2,7 +2,9 @@ mono_files += files(
|
|||
'iwrapper.cs',
|
||||
'workaround.cs',
|
||||
'FunctionWrapper.cs',
|
||||
'NativeModule.cs'
|
||||
'NativeModule.cs',
|
||||
'EoWrapper.cs',
|
||||
'WrapperSupervisor.cs'
|
||||
)
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
|
|
|
@ -44,12 +44,6 @@ public struct Efl_Object_Ops
|
|||
public UIntPtr count;
|
||||
};
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct EolianPD
|
||||
{
|
||||
public IntPtr pointer;
|
||||
}
|
||||
|
||||
#pragma warning disable 0169
|
||||
|
||||
public struct EvasObjectBoxLayout
|
||||
|
@ -115,8 +109,7 @@ 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);
|
||||
public delegate void FreeWrapperSupervisorCb(System.IntPtr obj);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct TextCursorCursor
|
||||
|
|
|
@ -148,6 +148,10 @@ if get_option('mono-beta')
|
|||
extra_cs_args += '-d:EFL_BETA'
|
||||
endif
|
||||
|
||||
if get_option('buildtype') == 'debug'
|
||||
extra_cs_args += '-d:EFL_DEBUG'
|
||||
endif
|
||||
|
||||
efl_mono_install_dir = join_paths(dir_lib, 'efl-mono-'+version_major)
|
||||
efl_mono_xml_doc = join_paths(meson.current_build_dir(), 'efl_mono.xml')
|
||||
|
||||
|
|
|
@ -23,44 +23,39 @@
|
|||
# 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)
|
||||
EAPI const char *efl_mono_wrapper_supervisor_key_get()
|
||||
{
|
||||
_efl_mono_free_gchandle_call = free_gchandle_cb;
|
||||
_efl_mono_remove_events_call = remove_events_cb;
|
||||
return "__c#_wrapper_supervisor";
|
||||
}
|
||||
|
||||
EAPI void efl_mono_native_dispose(Eo *obj, void* gchandle)
|
||||
EAPI void *efl_mono_wrapper_supervisor_get(Eo *eo)
|
||||
{
|
||||
if (gchandle) _efl_mono_remove_events_call(obj, gchandle);
|
||||
efl_unref(obj);
|
||||
if (gchandle) _efl_mono_free_gchandle_call(gchandle);
|
||||
return efl_key_data_get(eo, efl_mono_wrapper_supervisor_key_get());
|
||||
}
|
||||
|
||||
typedef struct _Efl_Mono_Native_Dispose_Data
|
||||
EAPI void efl_mono_wrapper_supervisor_set(Eo *eo, void *ws)
|
||||
{
|
||||
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);
|
||||
efl_key_data_set(eo, efl_mono_wrapper_supervisor_key_get(), ws);
|
||||
}
|
||||
|
||||
EAPI void efl_mono_thread_safe_native_dispose(Eo *obj, void* gchandle)
|
||||
typedef void (*Efl_Mono_Free_Wrapper_Supervisor_Cb)(Eo *obj);
|
||||
|
||||
static Efl_Mono_Free_Wrapper_Supervisor_Cb _efl_mono_free_wrapper_supervisor_call = NULL;
|
||||
|
||||
EAPI void efl_mono_wrapper_supervisor_callbacks_set(Efl_Mono_Free_Wrapper_Supervisor_Cb free_wrapper_supervisor_cb)
|
||||
{
|
||||
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);
|
||||
_efl_mono_free_wrapper_supervisor_call = free_wrapper_supervisor_cb;
|
||||
}
|
||||
|
||||
EAPI void efl_mono_native_dispose(Eo *obj)
|
||||
{
|
||||
_efl_mono_free_wrapper_supervisor_call(obj);
|
||||
}
|
||||
|
||||
EAPI void efl_mono_thread_safe_native_dispose(Eo *obj)
|
||||
{
|
||||
ecore_main_loop_thread_safe_call_async((Ecore_Cb)efl_mono_native_dispose, obj);
|
||||
}
|
||||
|
||||
static void _efl_mono_unref_cb(void *obj)
|
||||
|
|
|
@ -411,6 +411,11 @@ abstract Efl.Object
|
|||
del @hot: void; [[Object is being deleted. See @.destructor.]]
|
||||
invalidate @hot: void; [[Object is being invalidated and losing its parent. See @.invalidate.]]
|
||||
noref @hot: void; [[Object has lost its last reference, only parent relationship is keeping it alive. Advanced usage.]]
|
||||
ownership,unique @hot: void; [[Object has lost a reference and only one is left. It has just one owner now.
|
||||
Triggered whenever the refcount goes from two to one.]]
|
||||
ownership,shared @hot: void; [[Object has acquired a second reference. It has multiple owners now.
|
||||
Triggered whenever increasing the refcount from one to two,
|
||||
it will not trigger by further increasing the refcount beyond two.]]
|
||||
destruct @hot: void; [[Object has been fully destroyed. It can not be used
|
||||
beyond this point. This event should only serve to clean up any
|
||||
reference you keep to the object.]]
|
||||
|
|
|
@ -1933,6 +1933,9 @@ efl_ref(const Eo *obj_id)
|
|||
++(obj->user_refcount);
|
||||
if (EINA_UNLIKELY(obj->user_refcount == 1))
|
||||
_efl_ref(obj);
|
||||
else if (EINA_UNLIKELY(obj->ownership_track && obj->user_refcount == 2))
|
||||
efl_event_callback_call((Eo *) obj_id, EFL_EVENT_OWNERSHIP_SHARED, NULL);
|
||||
|
||||
#ifdef EO_DEBUG
|
||||
_eo_log_obj_ref_op(obj, EO_REF_OP_REF);
|
||||
#endif
|
||||
|
@ -1991,6 +1994,10 @@ efl_unref(const Eo *obj_id)
|
|||
}
|
||||
_efl_unref(obj);
|
||||
}
|
||||
else if (EINA_UNLIKELY(obj->ownership_track && obj->user_refcount == 1))
|
||||
{
|
||||
efl_event_callback_call((Eo *) obj_id, EFL_EVENT_OWNERSHIP_UNIQUE, NULL);
|
||||
}
|
||||
|
||||
_apply_auto_unref(obj, obj_id);
|
||||
|
||||
|
|
|
@ -1179,6 +1179,12 @@ _special_event_count_inc(Eo *obj_id, Efl_Object_Data *pd, const Efl_Callback_Arr
|
|||
}
|
||||
else if (it->desc == EFL_EVENT_DESTRUCT)
|
||||
pd->has_destroyed_event_cb = EINA_TRUE;
|
||||
else if (it->desc == EFL_EVENT_OWNERSHIP_SHARED || it->desc == EFL_EVENT_OWNERSHIP_UNIQUE)
|
||||
{
|
||||
EO_OBJ_POINTER_RETURN(obj_id, obj);
|
||||
obj->ownership_track = EINA_TRUE;
|
||||
EO_OBJ_DONE(obj_id);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
|
@ -126,6 +126,7 @@ struct _Eo_Object
|
|||
Eina_Bool destructed:1;
|
||||
Eina_Bool manual_free:1;
|
||||
unsigned char auto_unref : 1; // unref after 1 call - hack for parts
|
||||
Eina_Bool ownership_track:1;
|
||||
};
|
||||
|
||||
/* How we search and store the implementations in classes. */
|
||||
|
|
|
@ -122,8 +122,8 @@ enum class variable_type
|
|||
|
||||
|
||||
struct type_def;
|
||||
bool operator==(type_def const& rhs, type_def const& lhs);
|
||||
bool operator!=(type_def const& rhs, type_def const& lhs);
|
||||
bool operator==(type_def const& lhs, type_def const& rhs);
|
||||
bool operator!=(type_def const& lhs, type_def const& rhs);
|
||||
|
||||
enum class class_type
|
||||
{
|
||||
|
@ -377,8 +377,8 @@ struct type_def
|
|||
bool is_beta;
|
||||
|
||||
type_def() = default;
|
||||
type_def(variant_type original_type, std::string c_type, bool has_own)
|
||||
: original_type(original_type), c_type(c_type), has_own(has_own) {}
|
||||
type_def(variant_type original_type, std::string c_type, bool has_own, bool is_ptr, bool is_beta)
|
||||
: original_type(original_type), c_type(c_type), has_own(has_own), is_ptr(is_ptr), is_beta(is_beta) {}
|
||||
|
||||
type_def(Eolian_Type const* eolian_type, Eolian_Unit const* unit, Eolian_C_Type_Type ctype)
|
||||
{
|
||||
|
@ -422,7 +422,7 @@ inline bool operator!=(type_def const& lhs, type_def const& rhs)
|
|||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
type_def const void_ {attributes::regular_type_def{"void", {qualifier_info::is_none, {}}, {}}, "void", false};
|
||||
type_def const void_ {attributes::regular_type_def{"void", {qualifier_info::is_none, {}}, {}}, "void", false, false, false};
|
||||
|
||||
inline void type_def::set(Eolian_Type const* eolian_type, Eolian_Unit const* unit, Eolian_C_Type_Type ctype)
|
||||
{
|
||||
|
@ -699,6 +699,7 @@ struct function_def
|
|||
function_type _type,
|
||||
bool _is_beta = false,
|
||||
bool _is_protected = false,
|
||||
bool _is_static = false,
|
||||
Eolian_Unit const* unit = nullptr)
|
||||
: klass(_klass), return_type(_return_type), name(_name),
|
||||
parameters(_parameters), c_name(_c_name), filename(_filename),
|
||||
|
@ -708,6 +709,7 @@ struct function_def
|
|||
property_documentation(_property_documentation),
|
||||
type(_type),
|
||||
is_beta(_is_beta), is_protected(_is_protected),
|
||||
is_static(_is_static),
|
||||
unit(unit) {}
|
||||
|
||||
function_def( ::Eolian_Function const* function, Eolian_Function_Type type, Eolian_Typedecl const* tp, Eolian_Unit const* unit)
|
||||
|
@ -1191,7 +1193,7 @@ struct klass_def
|
|||
{
|
||||
return lhs.eolian_name == rhs.eolian_name
|
||||
&& lhs.cxx_name == rhs.cxx_name
|
||||
&& lhs.filename == lhs.filename
|
||||
&& lhs.filename == rhs.filename
|
||||
&& lhs.namespaces == rhs.namespaces
|
||||
&& lhs.functions == rhs.functions
|
||||
&& lhs.properties == rhs.properties
|
||||
|
@ -1223,7 +1225,8 @@ struct klass_def
|
|||
, class_type type
|
||||
, std::set<klass_name, compare_klass_name_by_name> immediate_inherits
|
||||
, std::string klass_get_name
|
||||
, bool is_beta)
|
||||
, bool is_beta
|
||||
, Eolian_Unit const* unit)
|
||||
: eolian_name(eolian_name), cxx_name(cxx_name), filename(filename)
|
||||
, documentation(documentation)
|
||||
, namespaces(namespaces)
|
||||
|
@ -1231,6 +1234,7 @@ struct klass_def
|
|||
, immediate_inherits(immediate_inherits)
|
||||
, klass_get_name(klass_get_name)
|
||||
, is_beta(is_beta)
|
||||
, unit(unit)
|
||||
{}
|
||||
klass_def(std::string _eolian_name, std::string _cxx_name
|
||||
, std::vector<std::string> _namespaces
|
||||
|
|
|
@ -110,6 +110,20 @@ class TestEoInherit
|
|||
Efl.Object loop = new MyObject();
|
||||
Test.Assert(loop.NativeHandle != System.IntPtr.Zero);
|
||||
}
|
||||
|
||||
private static WeakReference CreateCollectableInherited()
|
||||
{
|
||||
var obj = new MyObject();
|
||||
return new WeakReference(obj);
|
||||
}
|
||||
|
||||
public static void inherited_collected()
|
||||
{
|
||||
var wref = CreateCollectableInherited();
|
||||
Test.CollectAndIterate();
|
||||
|
||||
Test.AssertNull(wref.Target);
|
||||
}
|
||||
}
|
||||
|
||||
class TestEoNames
|
||||
|
@ -496,4 +510,23 @@ class TestProvider
|
|||
}
|
||||
}
|
||||
|
||||
class TestObjectDeletion
|
||||
{
|
||||
public static void test_object_deletion()
|
||||
{
|
||||
var obj = new Dummy.PartHolder();
|
||||
var part = obj.OnePart;
|
||||
|
||||
Test.AssertNotNull(part);
|
||||
|
||||
part.Del();
|
||||
|
||||
Test.AssertNull(obj.OnePart);
|
||||
|
||||
#if EFL_DEBUG
|
||||
Test.AssertRaises<ObjectDisposedException>(() => part.SetParent(null));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -274,4 +274,57 @@ class TestEventNaming
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
class TestEventWithDeadWrappers
|
||||
{
|
||||
|
||||
private static WeakReference AttachToManager(Dummy.EventManager manager,
|
||||
EventHandler<Dummy.TestObjectEvtWithIntEvt_Args> cb)
|
||||
{
|
||||
var obj = new Dummy.TestObject();
|
||||
manager.Emitter = obj;
|
||||
|
||||
obj.EvtWithIntEvt += cb;
|
||||
return new WeakReference(obj);
|
||||
}
|
||||
|
||||
public static void test_event_from_c_owned_wrapper()
|
||||
{
|
||||
// Set upon object instantiation
|
||||
WeakReference wref = null;
|
||||
|
||||
// Checks in the callback called
|
||||
bool callbackCalled = false;
|
||||
int received = -1;
|
||||
|
||||
// attach to evt with int
|
||||
EventHandler<Dummy.TestObjectEvtWithIntEvt_Args> cb = (object sender, Dummy.TestObjectEvtWithIntEvt_Args args) => {
|
||||
callbackCalled = true;
|
||||
received = args.arg;
|
||||
Test.Assert(Object.ReferenceEquals(sender, wref.Target));
|
||||
};
|
||||
|
||||
Dummy.EventManager manager = new Dummy.EventManager();
|
||||
wref = AttachToManager(manager, cb);
|
||||
|
||||
Test.CollectAndIterate();
|
||||
|
||||
manager.EmitWithInt(42);
|
||||
|
||||
Test.CollectAndIterate();
|
||||
|
||||
Test.Assert(callbackCalled, "Callback must have been called.");
|
||||
Test.AssertEquals(42, received, "Wrong value received.");
|
||||
|
||||
// Cleanup checks
|
||||
manager.Release();
|
||||
|
||||
// Make sure the released wrapper is collected and release the Eo object
|
||||
Test.CollectAndIterate();
|
||||
|
||||
Test.AssertNull(wref.Target);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,46 @@ class TestInheritance
|
|||
}
|
||||
}
|
||||
|
||||
internal class Inherit3Parent : Dummy.TestObject
|
||||
{
|
||||
public bool disposed = false;
|
||||
public bool childDisposed = false;
|
||||
|
||||
~Inherit3Parent()
|
||||
{
|
||||
Console.WriteLine("finalizer called for parent");
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
Console.WriteLine("Dispose parent");
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
internal class Inherit3Child : Dummy.TestObject
|
||||
{
|
||||
Inherit3Parent parent;
|
||||
public Inherit3Child(Inherit3Parent parent) : base(parent)
|
||||
{
|
||||
// WARNING: Uncommenting the line below causes the parent-child cycle to leak.
|
||||
// The GC won't be able to collect it.
|
||||
// this.parent = parent;
|
||||
}
|
||||
|
||||
~Inherit3Child()
|
||||
{
|
||||
Console.WriteLine("finalizer called for child");
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
/* parent.childDisposed = true; */
|
||||
Console.WriteLine("Dispose parent");
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
public static void test_inherit_from_regular_class()
|
||||
{
|
||||
var obj = new Inherit1();
|
||||
|
@ -50,6 +90,55 @@ class TestInheritance
|
|||
string s = Dummy.InheritHelper.ReceiveDummyAndCallInStringshare(obj);
|
||||
Test.AssertEquals ("Hello World", s);
|
||||
}
|
||||
|
||||
private static void CreateAndCheckInheritedObjects(out WeakReference parentWRef, out WeakReference childWRef)
|
||||
{
|
||||
var parent = new Inherit3Parent();
|
||||
var child = new Inherit3Child(parent);
|
||||
|
||||
parentWRef = new WeakReference(parent);
|
||||
childWRef = new WeakReference(child);
|
||||
|
||||
Console.WriteLine($"Parent [{parent.ToString()}] has {Efl.Eo.Globals.efl_ref_count(parent.NativeHandle)} refs");
|
||||
Console.WriteLine($"Child [{child.ToString()}] has {Efl.Eo.Globals.efl_ref_count(child.NativeHandle)} refs");
|
||||
|
||||
child = null;
|
||||
|
||||
System.GC.Collect(System.GC.MaxGeneration, GCCollectionMode.Forced, true, true);
|
||||
System.GC.WaitForPendingFinalizers();
|
||||
Efl.App.AppMain.Iterate();
|
||||
|
||||
child = (Inherit3Child) childWRef.Target;
|
||||
|
||||
Test.AssertNotNull(parent);
|
||||
Test.AssertNotNull(child);
|
||||
Test.AssertEquals(false, parent.disposed);
|
||||
Test.AssertEquals(false, parent.childDisposed);
|
||||
|
||||
Console.WriteLine($"Parent [{parent.ToString()}] has {Efl.Eo.Globals.efl_ref_count(parent.NativeHandle)} refs");
|
||||
Console.WriteLine($"Child [{child.ToString()}] has {Efl.Eo.Globals.efl_ref_count(child.NativeHandle)} refs");
|
||||
|
||||
parent = null;
|
||||
child = null;
|
||||
}
|
||||
|
||||
public static void test_inherit_lifetime()
|
||||
{
|
||||
WeakReference parentWRef;
|
||||
WeakReference childWRef;
|
||||
|
||||
CreateAndCheckInheritedObjects(out parentWRef, out childWRef);
|
||||
|
||||
// Two invocations to iterate a the child wasn't being released with a single one
|
||||
Test.CollectAndIterate();
|
||||
Test.CollectAndIterate();
|
||||
|
||||
var parent = (Dummy.TestObject) parentWRef.Target;
|
||||
var child = (Dummy.TestObject) childWRef.Target;
|
||||
|
||||
Test.AssertNull(parent);
|
||||
Test.AssertNull(child);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,6 +42,9 @@ class TestMain
|
|||
if (localTestCase == setUp || localTestCase == tearDown)
|
||||
continue;
|
||||
|
||||
// Cleanup garbage collector and job queue
|
||||
Test.CollectAndIterate(1);
|
||||
|
||||
Console.WriteLine("[ RUN ] " + testCase.Name + "." + localTestCase.Name);
|
||||
bool caseResult = true;
|
||||
|
||||
|
|
|
@ -43,13 +43,14 @@ public static class Test
|
|||
[CallerFilePath] string file = null,
|
||||
[CallerMemberName] string member = null)
|
||||
{
|
||||
if (file == null)
|
||||
file = "(unknown file)";
|
||||
if (member == null)
|
||||
member = "(unknown member)";
|
||||
if (expected == null)
|
||||
throw new AssertionException($"{file}:{line} ({member}) Null expected value. Use AssertNull.");
|
||||
if (!expected.Equals(actual)) {
|
||||
if (expected == null && actual == null)
|
||||
return;
|
||||
if (expected == null || !expected.Equals(actual))
|
||||
{
|
||||
if (file == null)
|
||||
file = "(unknown file)";
|
||||
if (member == null)
|
||||
member = "(unknown member)";
|
||||
if (msg == null || msg.Length == 0)
|
||||
msg = $"Expected \"{expected}\", actual \"{actual}\"";
|
||||
throw new AssertionException($"{file}:{line} ({member}) {msg}");
|
||||
|
@ -62,13 +63,12 @@ public static class Test
|
|||
[CallerFilePath] string file = null,
|
||||
[CallerMemberName] string member = null)
|
||||
{
|
||||
if (file == null)
|
||||
file = "(unknown file)";
|
||||
if (member == null)
|
||||
member = "(unknown member)";
|
||||
if (expected == null)
|
||||
throw new AssertionException($"{file}:{line} ({member}) Null expected value. Use AssertNull.");
|
||||
if (expected.Equals(actual)) {
|
||||
if (expected == null ? actual == null : expected.Equals(actual))
|
||||
{
|
||||
if (file == null)
|
||||
file = "(unknown file)";
|
||||
if (member == null)
|
||||
member = "(unknown member)";
|
||||
if (msg == null || msg.Length == 0)
|
||||
msg = $"Expected \"{expected}\" shouldn't be equal to actual \"{actual}\"";
|
||||
throw new AssertionException($"{file}:{line} ({member}) {msg}");
|
||||
|
@ -196,6 +196,20 @@ public static class Test
|
|||
if (reference == null)
|
||||
throw new AssertionException($"Assertion failed: {file}:{line} ({member}) {msg}");
|
||||
}
|
||||
|
||||
/// <summary>Runs a number of garbage collections and iterate the main loop.
|
||||
/// The iteration is needed to make sure objects collected in the GC thread
|
||||
/// are efl_unref'd in the main thread.</summary>
|
||||
public static void CollectAndIterate(int iterations=1000)
|
||||
{
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
System.GC.Collect();
|
||||
}
|
||||
System.GC.WaitForPendingFinalizers();
|
||||
Efl.App.AppMain.Iterate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
#include "libefl_mono_native_test.h"
|
||||
|
||||
typedef struct Dummy_Event_Manager_Data
|
||||
{
|
||||
Eo* emitter;
|
||||
} Dummy_Event_Manager_Data;
|
||||
|
||||
static Efl_Object*
|
||||
_dummy_event_manager_efl_object_constructor(Eo *obj, EINA_UNUSED Dummy_Event_Manager_Data *pd)
|
||||
{
|
||||
efl_constructor(efl_super(obj, DUMMY_EVENT_MANAGER_CLASS));
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void
|
||||
_dummy_event_manager_efl_object_destructor(Eo *obj, Dummy_Event_Manager_Data *pd)
|
||||
{
|
||||
if (pd->emitter != 0)
|
||||
efl_unref(pd->emitter);
|
||||
|
||||
efl_destructor(efl_super(obj, DUMMY_EVENT_MANAGER_CLASS));
|
||||
}
|
||||
|
||||
static void
|
||||
_dummy_event_manager_emitter_set(EINA_UNUSED Eo *obj, Dummy_Event_Manager_Data *pd, Eo *emitter)
|
||||
{
|
||||
pd->emitter = emitter;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_dummy_event_manager_emit_with_int(EINA_UNUSED Eo *obj, Dummy_Event_Manager_Data *pd, int data)
|
||||
{
|
||||
if (pd->emitter)
|
||||
efl_event_callback_call(pd->emitter, DUMMY_TEST_OBJECT_EVENT_EVT_WITH_INT, &data);
|
||||
else
|
||||
{
|
||||
EINA_LOG_ERR("Trying to emit event without an emitter.");
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_dummy_event_manager_release(EINA_UNUSED Eo *obj, Dummy_Event_Manager_Data *pd)
|
||||
{
|
||||
if (!pd->emitter)
|
||||
return;
|
||||
|
||||
efl_unref(pd->emitter);
|
||||
}
|
||||
|
||||
|
||||
#include "dummy_event_manager.eo.c"
|
|
@ -0,0 +1,29 @@
|
|||
import eina_types;
|
||||
|
||||
class @beta Dummy.Event_Manager extends Efl.Object {
|
||||
|
||||
methods {
|
||||
@property emitter {
|
||||
set {
|
||||
}
|
||||
values {
|
||||
emitter: Efl.Object @owned;
|
||||
}
|
||||
}
|
||||
|
||||
emit_with_int {
|
||||
params {
|
||||
data: int;
|
||||
}
|
||||
return: bool;
|
||||
}
|
||||
|
||||
release {
|
||||
}
|
||||
}
|
||||
|
||||
implements {
|
||||
Efl.Object.constructor;
|
||||
Efl.Object.destructor;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,16 @@ typedef struct Dummy_Part_Holder_Data
|
|||
Eo *two;
|
||||
} Dummy_Part_Holder_Data;
|
||||
|
||||
void part_deleted_cb(void *data, const Efl_Event *evt)
|
||||
{
|
||||
Dummy_Part_Holder_Data *pd = data;
|
||||
|
||||
if (evt->object == pd->one)
|
||||
pd->one = NULL;
|
||||
else if (evt->object == pd->two)
|
||||
pd->two = NULL;
|
||||
}
|
||||
|
||||
// Part holder
|
||||
static Efl_Object*
|
||||
_dummy_part_holder_efl_object_constructor(Eo *obj, Dummy_Part_Holder_Data *pd)
|
||||
|
@ -16,12 +26,25 @@ _dummy_part_holder_efl_object_constructor(Eo *obj, Dummy_Part_Holder_Data *pd)
|
|||
if (!efl_parent_get(obj))
|
||||
{
|
||||
pd->one = efl_add(DUMMY_TEST_OBJECT_CLASS, obj, efl_name_set(efl_added, "part_one"));
|
||||
efl_event_callback_add(pd->one, EFL_EVENT_DEL, part_deleted_cb, pd);
|
||||
pd->two = efl_add(DUMMY_TEST_OBJECT_CLASS, obj, efl_name_set(efl_added, "part_two"));
|
||||
efl_event_callback_add(pd->two, EFL_EVENT_DEL, part_deleted_cb, pd);
|
||||
|
||||
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void
|
||||
_dummy_part_holder_efl_object_destructor(EINA_UNUSED Eo* obj, Dummy_Part_Holder_Data *pd)
|
||||
{
|
||||
if (pd->one)
|
||||
efl_parent_set(pd->one, NULL);
|
||||
if (pd->two)
|
||||
efl_parent_set(pd->two, NULL);
|
||||
}
|
||||
|
||||
Efl_Object *_dummy_part_holder_efl_part_part_get(EINA_UNUSED const Eo *obj, Dummy_Part_Holder_Data *pd, const char *name)
|
||||
{
|
||||
if (!strcmp(name, "one"))
|
||||
|
|
|
@ -9,5 +9,6 @@ class @beta Dummy.Part_Holder extends Dummy.Test_Object implements Efl.Part {
|
|||
implements {
|
||||
Efl.Part.part_get;
|
||||
Efl.Object.constructor;
|
||||
Efl.Object.destructor;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include "dummy_child.eo.h"
|
||||
#include "dummy_inherit_helper.eo.h"
|
||||
#include "dummy_part_holder.eo.h"
|
||||
#include "dummy_event_manager.eo.h"
|
||||
|
||||
#include <interfaces/efl_part.eo.h>
|
||||
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
eo_files = ['dummy_child.eo', 'dummy_numberwrapper.eo', 'dummy_test_object.eo', 'dummy_test_iface.eo', 'dummy_inherit_helper.eo', 'dummy_inherit_iface.eo', 'dummy_part_holder.eo']
|
||||
eo_files = [
|
||||
'dummy_child.eo',
|
||||
'dummy_numberwrapper.eo',
|
||||
'dummy_test_object.eo',
|
||||
'dummy_test_iface.eo',
|
||||
'dummy_inherit_helper.eo',
|
||||
'dummy_inherit_iface.eo',
|
||||
'dummy_part_holder.eo',
|
||||
'dummy_event_manager.eo',
|
||||
]
|
||||
|
||||
eo_file_targets = []
|
||||
|
||||
|
@ -23,6 +32,7 @@ efl_mono_native_test = library('efl_mono_native_test',
|
|||
'dummy_numberwrapper.c',
|
||||
'dummy_part_holder.c',
|
||||
'dummy_test_object.c',
|
||||
'dummy_event_manager.c',
|
||||
],
|
||||
dependencies : [ecore, eo, efl],
|
||||
)
|
||||
|
@ -100,7 +110,7 @@ custom_target('copy_efl_mono_lib_dll',
|
|||
endif
|
||||
|
||||
config_libs = ['eina', 'ecore', 'eo', 'efl', 'evas', 'eldbus', 'elementary']
|
||||
load_lib = ''
|
||||
load_lib = efl_mono_test_suite_path + ':'
|
||||
|
||||
foreach config : config_libs
|
||||
lib = get_variable(config+'_lib')
|
||||
|
|
|
@ -162,6 +162,238 @@ EFL_START_TEST(eo_test_unref_noref)
|
|||
}
|
||||
EFL_END_TEST
|
||||
|
||||
typedef struct {
|
||||
int shared, unique, invalidate;
|
||||
} OwnershipEventsCounter;
|
||||
|
||||
static void
|
||||
_ownership_shared_event(void *data, const Efl_Event *ev EINA_UNUSED)
|
||||
{
|
||||
OwnershipEventsCounter *counter = data;
|
||||
++(counter->shared);
|
||||
}
|
||||
|
||||
static void
|
||||
_ownership_unique_event(void *data, const Efl_Event *ev EINA_UNUSED)
|
||||
{
|
||||
OwnershipEventsCounter *counter = data;
|
||||
++(counter->unique);
|
||||
}
|
||||
|
||||
static void
|
||||
_invalidate_ownership_event(void *data, const Efl_Event *ev EINA_UNUSED)
|
||||
{
|
||||
OwnershipEventsCounter *counter = data;
|
||||
++(counter->invalidate);
|
||||
}
|
||||
|
||||
|
||||
EFL_START_TEST(eo_test_ownership_events)
|
||||
{
|
||||
OwnershipEventsCounter counter = {0,};
|
||||
Eo *obj = efl_add_ref(SIMPLE_CLASS, NULL);
|
||||
|
||||
efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
|
||||
efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
|
||||
efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
|
||||
|
||||
efl_ref(obj);
|
||||
ck_assert_int_eq(counter.shared, 1);
|
||||
ck_assert_int_eq(counter.unique, 0);
|
||||
|
||||
efl_unref(obj);
|
||||
ck_assert_int_eq(counter.shared, 1);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
|
||||
efl_ref(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
efl_ref(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
efl_ref(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
|
||||
efl_unref(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
efl_unref(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
efl_unref(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 2);
|
||||
ck_assert_int_eq(counter.invalidate, 0);
|
||||
|
||||
efl_unref(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 2);
|
||||
ck_assert_int_eq(counter.invalidate, 1);
|
||||
}
|
||||
EFL_END_TEST
|
||||
|
||||
EFL_START_TEST(eo_test_ownership_events_with_parent)
|
||||
{
|
||||
OwnershipEventsCounter counter = {0,};
|
||||
Eo *par = efl_add_ref(SIMPLE_CLASS, NULL);
|
||||
Eo *obj = efl_add(SIMPLE_CLASS, par);
|
||||
|
||||
efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
|
||||
efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
|
||||
efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
|
||||
|
||||
efl_ref(obj);
|
||||
ck_assert_int_eq(counter.shared, 1);
|
||||
ck_assert_int_eq(counter.unique, 0);
|
||||
|
||||
efl_unref(obj);
|
||||
ck_assert_int_eq(counter.shared, 1);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
|
||||
efl_ref(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
efl_ref(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
|
||||
efl_unref(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
efl_unref(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 2);
|
||||
ck_assert_int_eq(counter.invalidate, 0);
|
||||
|
||||
efl_del(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 2);
|
||||
ck_assert_int_eq(counter.invalidate, 1);
|
||||
|
||||
efl_unref(par);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 2);
|
||||
}
|
||||
EFL_END_TEST
|
||||
|
||||
EFL_START_TEST(eo_test_ownership_events_with_parent_invalidate)
|
||||
{
|
||||
OwnershipEventsCounter counter = {0,};
|
||||
Eo *par = efl_add_ref(SIMPLE_CLASS, NULL);
|
||||
Eo *obj = efl_add(SIMPLE_CLASS, par);
|
||||
|
||||
efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
|
||||
efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
|
||||
efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
|
||||
|
||||
/* Kill parent */
|
||||
efl_unref(par);
|
||||
ck_assert_int_eq(counter.shared, 0);
|
||||
ck_assert_int_eq(counter.unique, 0);
|
||||
ck_assert_int_eq(counter.invalidate, 1);
|
||||
}
|
||||
EFL_END_TEST
|
||||
|
||||
EFL_START_TEST(eo_test_ownership_events_with_parent_invalidate2)
|
||||
{
|
||||
OwnershipEventsCounter counter = {0,};
|
||||
Eo *par = efl_add_ref(SIMPLE_CLASS, NULL);
|
||||
Eo *obj = efl_add(SIMPLE_CLASS, par);
|
||||
|
||||
efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
|
||||
efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
|
||||
efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
|
||||
|
||||
efl_ref(obj);
|
||||
ck_assert_int_eq(counter.shared, 1);
|
||||
ck_assert_int_eq(counter.unique, 0);
|
||||
ck_assert_int_eq(counter.invalidate, 0);
|
||||
|
||||
/* Kill parent */
|
||||
efl_unref(par);
|
||||
ck_assert_int_eq(counter.shared, 1);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
ck_assert_int_eq(counter.invalidate, 1);
|
||||
|
||||
efl_unref(obj);
|
||||
ck_assert_int_eq(counter.shared, 1);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
ck_assert_int_eq(counter.invalidate, 1);
|
||||
}
|
||||
EFL_END_TEST
|
||||
|
||||
EFL_START_TEST(eo_test_ownership_events_with_parent_invalidate3)
|
||||
{
|
||||
OwnershipEventsCounter counter = {0,};
|
||||
Eo *par = efl_add_ref(SIMPLE_CLASS, NULL);
|
||||
Eo *obj = efl_add(SIMPLE_CLASS, par);
|
||||
|
||||
efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
|
||||
efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
|
||||
efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
|
||||
|
||||
efl_ref(obj);
|
||||
ck_assert_int_eq(counter.shared, 1);
|
||||
ck_assert_int_eq(counter.unique, 0);
|
||||
|
||||
efl_unref(obj);
|
||||
ck_assert_int_eq(counter.shared, 1);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
|
||||
efl_ref(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
efl_ref(obj);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
ck_assert_int_eq(counter.invalidate, 0);
|
||||
|
||||
/* Kill parent */
|
||||
efl_unref(par);
|
||||
ck_assert_int_eq(counter.shared, 2);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
ck_assert_int_eq(counter.invalidate, 1);
|
||||
}
|
||||
EFL_END_TEST
|
||||
|
||||
EFL_START_TEST(eo_test_ownership_events_self_invalidate)
|
||||
{
|
||||
OwnershipEventsCounter counter = {0,};
|
||||
Eo *par = efl_add_ref(SIMPLE_CLASS, NULL);
|
||||
Eo *obj = efl_add(SIMPLE_CLASS, par);
|
||||
|
||||
efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_SHARED, _ownership_shared_event, &counter);
|
||||
efl_event_callback_add(obj, EFL_EVENT_OWNERSHIP_UNIQUE, _ownership_unique_event, &counter);
|
||||
efl_event_callback_add(obj, EFL_EVENT_INVALIDATE, _invalidate_ownership_event, &counter);
|
||||
|
||||
ck_assert_int_eq(counter.shared, 0);
|
||||
ck_assert_int_eq(counter.unique, 0);
|
||||
ck_assert_int_eq(counter.invalidate, 0);
|
||||
|
||||
efl_ref(obj);
|
||||
ck_assert_int_eq(counter.shared, 1);
|
||||
ck_assert_int_eq(counter.unique, 0);
|
||||
ck_assert_int_eq(counter.invalidate, 0);
|
||||
|
||||
efl_del(obj);
|
||||
ck_assert_int_eq(counter.shared, 1);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
ck_assert_int_eq(counter.invalidate, 1);
|
||||
|
||||
/* Kill parent */
|
||||
efl_unref(par);
|
||||
ck_assert_int_eq(counter.shared, 1);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
ck_assert_int_eq(counter.invalidate, 1);
|
||||
|
||||
efl_unref(obj);
|
||||
ck_assert_int_eq(counter.shared, 1);
|
||||
ck_assert_int_eq(counter.unique, 1);
|
||||
ck_assert_int_eq(counter.invalidate, 1);
|
||||
}
|
||||
EFL_END_TEST
|
||||
|
||||
typedef struct {
|
||||
Eo *par;
|
||||
Eina_Bool called;
|
||||
|
@ -216,6 +448,12 @@ void eo_test_lifecycle(TCase *tc)
|
|||
tcase_add_test(tc, eo_test_shutdown_eventting);
|
||||
tcase_add_test(tc, eo_test_del_in_noref);
|
||||
tcase_add_test(tc, eo_test_unref_noref);
|
||||
tcase_add_test(tc, eo_test_ownership_events);
|
||||
tcase_add_test(tc, eo_test_ownership_events_with_parent);
|
||||
tcase_add_test(tc, eo_test_ownership_events_with_parent_invalidate);
|
||||
tcase_add_test(tc, eo_test_ownership_events_with_parent_invalidate2);
|
||||
tcase_add_test(tc, eo_test_ownership_events_with_parent_invalidate3);
|
||||
tcase_add_test(tc, eo_test_ownership_events_self_invalidate);
|
||||
tcase_add_test(tc, eo_test_invalidating_get);
|
||||
tcase_add_test(tc, eo_test_alive_get);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue