summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-06-04 18:43:07 -0300
committerVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-06-04 19:42:55 -0300
commitf6eeb3fb7c00045c99e8c5559583f8d2c96f8909 (patch)
tree3e634f35467545380f96e5fcca20d410a5a1292f
parentc2865a90ef75320f5ceb00abb03076b8363aa867 (diff)
csharp: make inherited C# classes constructible from native C
Summary: With this commit it is now possible for a class that inherits from a C# binding class to be instantiated from native C code. It only has to provide a constructor that receives an `Efl.Eo.EoWrapper.ConstructingHandle` struct, and which calls the base binding constructor passing it. For example: `private Type(ConstructingHandle ch) : base(ch) {}`. Add some test files to validate the proper behavior of this feature. Add some small fixes in generation contexts in order to properly generate base constructors. Depends on D9070 Test Plan: `meson test` and `make check` Reviewers: lauromoura, felipealmeida, segfaultxavi, woohyun Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9071
-rw-r--r--src/Makefile_Efl_Mono.am9
-rw-r--r--src/bin/eolian_mono/eolian/mono/klass.hh24
-rw-r--r--src/bindings/mono/eo_mono/EoWrapper.cs105
-rw-r--r--src/bindings/mono/eo_mono/iwrapper.cs11
-rw-r--r--src/lib/efl_mono/efl_custom_exports_mono.c10
-rw-r--r--src/tests/efl_mono/EoConstruction.cs79
-rw-r--r--src/tests/efl_mono/dummy_constructible_object.c70
-rw-r--r--src/tests/efl_mono/dummy_constructible_object.eo47
-rw-r--r--src/tests/efl_mono/dummy_test_object.c6
-rw-r--r--src/tests/efl_mono/libefl_mono_native_test.h1
-rw-r--r--src/tests/efl_mono/meson.build3
11 files changed, 352 insertions, 13 deletions
diff --git a/src/Makefile_Efl_Mono.am b/src/Makefile_Efl_Mono.am
index 0cf41589ff..3d04368ccf 100644
--- a/src/Makefile_Efl_Mono.am
+++ b/src/Makefile_Efl_Mono.am
@@ -70,6 +70,7 @@ efl_mono_test_eolian_files = \
70 tests/efl_mono/dummy_inherit_iface.eo \ 70 tests/efl_mono/dummy_inherit_iface.eo \
71 tests/efl_mono/dummy_inherit_helper.eo \ 71 tests/efl_mono/dummy_inherit_helper.eo \
72 tests/efl_mono/dummy_child.eo \ 72 tests/efl_mono/dummy_child.eo \
73 tests/efl_mono/dummy_constructible_object.eo \
73 tests/efl_mono/dummy_part_holder.eo \ 74 tests/efl_mono/dummy_part_holder.eo \
74 tests/efl_mono/dummy_numberwrapper.eo \ 75 tests/efl_mono/dummy_numberwrapper.eo \
75 tests/efl_mono/dummy_event_manager.eo 76 tests/efl_mono/dummy_event_manager.eo
@@ -403,6 +404,7 @@ tests_efl_mono_libefl_mono_native_test_la_SOURCES = \
403 tests/efl_mono/dummy_interfaces.c \ 404 tests/efl_mono/dummy_interfaces.c \
404 tests/efl_mono/dummy_numberwrapper.c \ 405 tests/efl_mono/dummy_numberwrapper.c \
405 tests/efl_mono/dummy_part_holder.c \ 406 tests/efl_mono/dummy_part_holder.c \
407 tests/efl_mono/dummy_constructible_object.c \
406 tests/efl_mono/dummy_test_object.c 408 tests/efl_mono/dummy_test_object.c
407 409
408efl_mono_test_eolian_c = $(efl_mono_test_eolian_files:%.eo=%.eo.c) 410efl_mono_test_eolian_c = $(efl_mono_test_eolian_files:%.eo=%.eo.c)
@@ -447,6 +449,11 @@ tests/efl_mono/dummy_part_holder.c: \
447 $(efl_mono_test_eolian_h) \ 449 $(efl_mono_test_eolian_h) \
448 tests/efl_mono/libefl_mono_native_test.h 450 tests/efl_mono/libefl_mono_native_test.h
449 451
452tests/efl_mono/dummy_constructible_object.c: \
453 $(efl_mono_test_eolian_c) \
454 $(efl_mono_test_eolian_h) \
455 tests/efl_mono/libefl_mono_native_test.h
456
450tests/efl_mono/dummy_test_object.c: \ 457tests/efl_mono/dummy_test_object.c: \
451 $(efl_mono_test_eolian_c) \ 458 $(efl_mono_test_eolian_c) \
452 $(efl_mono_test_eolian_h) \ 459 $(efl_mono_test_eolian_h) \
@@ -455,6 +462,7 @@ tests/efl_mono/dummy_test_object.c: \
455# Intermediate C Sharp test DLL 462# Intermediate C Sharp test DLL
456efl_mono_test_eolian_mono_files = tests/efl_mono/dummy_test_object.eo.cs \ 463efl_mono_test_eolian_mono_files = tests/efl_mono/dummy_test_object.eo.cs \
457tests/efl_mono/dummy_test_iface.eo.cs \ 464tests/efl_mono/dummy_test_iface.eo.cs \
465tests/efl_mono/dummy_constructible_object.eo.cs \
458tests/efl_mono/dummy_child.eo.cs \ 466tests/efl_mono/dummy_child.eo.cs \
459tests/efl_mono/dummy_event_manager.eo.cs \ 467tests/efl_mono/dummy_event_manager.eo.cs \
460tests/efl_mono/dummy_part_holder.eo.cs \ 468tests/efl_mono/dummy_part_holder.eo.cs \
@@ -509,6 +517,7 @@ tests_efl_mono_efl_mono_SOURCES = \
509 tests/efl_mono/Eldbus.cs \ 517 tests/efl_mono/Eldbus.cs \
510 tests/efl_mono/Eo.cs \ 518 tests/efl_mono/Eo.cs \
511 tests/efl_mono/EoPromises.cs \ 519 tests/efl_mono/EoPromises.cs \
520 tests/efl_mono/EoConstruction.cs \
512 tests/efl_mono/Errors.cs \ 521 tests/efl_mono/Errors.cs \
513 tests/efl_mono/Events.cs \ 522 tests/efl_mono/Events.cs \
514 tests/efl_mono/FunctionPointers.cs \ 523 tests/efl_mono/FunctionPointers.cs \
diff --git a/src/bin/eolian_mono/eolian/mono/klass.hh b/src/bin/eolian_mono/eolian/mono/klass.hh
index 6ac4aa1c3c..8b018f6413 100644
--- a/src/bin/eolian_mono/eolian/mono/klass.hh
+++ b/src/bin/eolian_mono/eolian/mono/klass.hh
@@ -198,6 +198,17 @@ struct klass
198 198
199 if (!as_generator 199 if (!as_generator
200 ( 200 (
201 scope_tab << "/// <summary>Constructor to be used when objects are expected to be constructed from native code.</summary>\n"
202 << scope_tab << "/// <param name=\"ch\">Tag struct storing the native handle of the object being constructed.</param>\n"
203 << scope_tab << "private " << concrete_name << "(ConstructingHandle ch) : base(ch)\n"
204 << scope_tab << "{\n"
205 << scope_tab << "}\n\n"
206 )
207 .generate(sink, attributes::unused, concrete_cxt))
208 return false;
209
210 if (!as_generator
211 (
201 scope_tab << "[System.Runtime.InteropServices.DllImport(" << context_find_tag<library_context>(concrete_cxt).actual_library_name(cls.filename) 212 scope_tab << "[System.Runtime.InteropServices.DllImport(" << context_find_tag<library_context>(concrete_cxt).actual_library_name(cls.filename)
202 << ")] internal static extern System.IntPtr\n" 213 << ")] internal static extern System.IntPtr\n"
203 << scope_tab << scope_tab << name_helpers::klass_get_name(cls) << "();\n" 214 << scope_tab << scope_tab << name_helpers::klass_get_name(cls) << "();\n"
@@ -246,7 +257,7 @@ struct klass
246 ).generate(sink, attributes::unused, concrete_cxt)) 257 ).generate(sink, attributes::unused, concrete_cxt))
247 return false; 258 return false;
248 259
249 if(!generate_native_inherit_class(sink, cls, change_indentation(indent.inc(), context))) 260 if(!generate_native_inherit_class(sink, cls, change_indentation(indent.inc(), concrete_cxt)))
250 return true; 261 return true;
251 262
252 if(!as_generator("}\n").generate(sink, attributes::unused, concrete_cxt)) return false; 263 if(!as_generator("}\n").generate(sink, attributes::unused, concrete_cxt)) return false;
@@ -318,7 +329,7 @@ struct klass
318 ).generate(sink, attributes::unused, inherit_cxt)) 329 ).generate(sink, attributes::unused, inherit_cxt))
319 return false; 330 return false;
320 331
321 if(!generate_native_inherit_class(sink, cls, change_indentation(indent.inc(), context))) 332 if(!generate_native_inherit_class(sink, cls, change_indentation(indent.inc(), inherit_cxt)))
322 return true; 333 return true;
323 334
324 if(!as_generator("}\n").generate(sink, attributes::unused, inherit_cxt)) return false; 335 if(!as_generator("}\n").generate(sink, attributes::unused, inherit_cxt)) return false;
@@ -357,7 +368,7 @@ struct klass
357 ( 368 (
358 indent << lit("/// <summary>Wrapper for native methods and virtual method delegates.\n") 369 indent << lit("/// <summary>Wrapper for native methods and virtual method delegates.\n")
359 << indent << "/// For internal use by generated code only.</summary>\n" 370 << indent << "/// For internal use by generated code only.</summary>\n"
360 << indent << "public " << (root ? "" : "new " ) << "class " << native_inherit_name << " " << (root ? " : Efl.Eo.NativeClass" : (": " + base_name)) <<"\n" 371 << indent << "public new class " << native_inherit_name << " : " << (root ? "Efl.Eo.EoWrapper.NativeMethods" : base_name) << "\n"
361 << indent << "{\n" 372 << indent << "{\n"
362 ).generate(sink, attributes::unused, inative_cxt)) 373 ).generate(sink, attributes::unused, inative_cxt))
363 return false; 374 return false;
@@ -396,7 +407,7 @@ struct klass
396 ).generate(sink, attributes::unused, inative_cxt)) 407 ).generate(sink, attributes::unused, inative_cxt))
397 return false; 408 return false;
398 409
399 if(!root) 410 if (!root || context_find_tag<class_context>(context).current_wrapper_kind != class_context::concrete)
400 if(!as_generator(indent << scope_tab << scope_tab << "descs.AddRange(base.GetEoOps(type));\n").generate(sink, attributes::unused, inative_cxt)) 411 if(!as_generator(indent << scope_tab << scope_tab << "descs.AddRange(base.GetEoOps(type));\n").generate(sink, attributes::unused, inative_cxt))
401 return false; 412 return false;
402 413
@@ -492,6 +503,11 @@ struct klass
492 << (*(scope_tab << scope_tab << constructor_invocation << "\n")) 503 << (*(scope_tab << scope_tab << constructor_invocation << "\n"))
493 << scope_tab << scope_tab << "FinishInstantiation();\n" 504 << scope_tab << scope_tab << "FinishInstantiation();\n"
494 << scope_tab << "}\n\n" 505 << scope_tab << "}\n\n"
506 << scope_tab << "/// <summary>Constructor to be used when objects are expected to be constructed from native code.</summary>\n"
507 << scope_tab << "/// <param name=\"ch\">Tag struct storing the native handle of the object being constructed.</param>\n"
508 << scope_tab << "protected " << inherit_name << "(ConstructingHandle ch) : base(ch)\n"
509 << scope_tab << "{\n"
510 << scope_tab << "}\n\n"
495 << scope_tab << "/// <summary>Initializes a new instance of the <see cref=\"" << inherit_name << "\"/> class.\n" 511 << scope_tab << "/// <summary>Initializes a new instance of the <see cref=\"" << inherit_name << "\"/> class.\n"
496 << 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" 512 << 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"
497 << scope_tab << "/// <param name=\"raw\">The native pointer to be wrapped.</param>\n" 513 << scope_tab << "/// <param name=\"raw\">The native pointer to be wrapped.</param>\n"
diff --git a/src/bindings/mono/eo_mono/EoWrapper.cs b/src/bindings/mono/eo_mono/EoWrapper.cs
index e1174a9fe8..0899b8682c 100644
--- a/src/bindings/mono/eo_mono/EoWrapper.cs
+++ b/src/bindings/mono/eo_mono/EoWrapper.cs
@@ -2,6 +2,7 @@ using System;
2using System.Runtime.InteropServices; 2using System.Runtime.InteropServices;
3using System.Runtime.CompilerServices; 3using System.Runtime.CompilerServices;
4using System.Threading; 4using System.Threading;
5using System.Reflection;
5 6
6namespace Efl 7namespace Efl
7{ 8{
@@ -62,6 +63,32 @@ public abstract class EoWrapper : IWrapper, IDisposable
62 private static Efl.EventCb ownershipUniqueDelegate = new Efl.EventCb(OwnershipUniqueCallback); 63 private static Efl.EventCb ownershipUniqueDelegate = new Efl.EventCb(OwnershipUniqueCallback);
63 private static Efl.EventCb ownershipSharedDelegate = new Efl.EventCb(OwnershipSharedCallback); 64 private static Efl.EventCb ownershipSharedDelegate = new Efl.EventCb(OwnershipSharedCallback);
64 65
66
67 /// <summary>Constructor to be used when objects are expected to be constructed from native code.
68 /// For a class that inherited from an EFL# class to be properly constructed from native code
69 /// one must create a constructor with this signature and calls this base constructor from it.
70 /// This constructor will take care of calling base constructors of the native classes and
71 /// perform additional setup so objects are ready to use.
72 /// It is advisable to check for the <see cref="NativeHandle"/> property in the top level
73 /// constructor and signal an error when it has a value of IntPtr.Zero after this
74 /// constructor completion.
75 /// Warning: Do not use this constructor directly from a `new` statement.</summary>
76 /// <param name="ch">Tag struct storing the native handle of the object being constructed.</param>
77 protected EoWrapper(ConstructingHandle ch)
78 {
79 handle = Efl.Eo.Globals.efl_constructor(Efl.Eo.Globals.efl_super(ch.NativeHandle, Efl.Eo.Globals.efl_class_get(ch.NativeHandle)));
80 if (handle == IntPtr.Zero)
81 {
82 Eina.Log.Warning("Natice constructor returned NULL");
83 return;
84 }
85
86 AddWrapperSupervisor();
87 // Make an additional reference to C#
88 // - Will also call EVENT_OWNERSHIP_SHARED
89 Efl.Eo.Globals.efl_ref(handle);
90 }
91
65 /// <summary>Initializes a new instance of the <see cref="Object"/> class. 92 /// <summary>Initializes a new instance of the <see cref="Object"/> class.
66 /// Internal usage: Constructs an instance from a native pointer. This is used when interacting with C code and should not be used directly.</summary> 93 /// Internal usage: Constructs an instance from a native pointer. This is used when interacting with C code and should not be used directly.</summary>
67 /// <param name="raw">The native pointer to be wrapped.</param> 94 /// <param name="raw">The native pointer to be wrapped.</param>
@@ -98,7 +125,17 @@ public abstract class EoWrapper : IWrapper, IDisposable
98 parent_ptr = parent.NativeHandle; 125 parent_ptr = parent.NativeHandle;
99 } 126 }
100 127
101 handle = Efl.Eo.Globals._efl_add_internal_start(file, line, actual_klass, parent_ptr, 1, 0); 128 if (!inherited)
129 {
130 handle = Efl.Eo.Globals._efl_add_internal_start(file, line, actual_klass, parent_ptr, 1, 0);
131 }
132 else
133 {
134 handle = Efl.Eo.Globals._efl_add_internal_start_bindings(file, line, actual_klass, parent_ptr, 1, 0,
135 Efl.Eo.Globals.efl_mono_avoid_top_level_constructor_callback_addr_get(),
136 IntPtr.Zero);
137 }
138
102 if (handle == System.IntPtr.Zero) 139 if (handle == System.IntPtr.Zero)
103 { 140 {
104 throw new Exception("Instantiation failed"); 141 throw new Exception("Instantiation failed");
@@ -297,8 +334,72 @@ public abstract class EoWrapper : IWrapper, IDisposable
297 AddNativeEventHandler("eo", "_EFL_EVENT_OWNERSHIP_SHARED", ownershipSharedDelegate, ownershipSharedDelegate); 334 AddNativeEventHandler("eo", "_EFL_EVENT_OWNERSHIP_SHARED", ownershipSharedDelegate, ownershipSharedDelegate);
298 Eina.Error.RaiseIfUnhandledException(); 335 Eina.Error.RaiseIfUnhandledException();
299 } 336 }
337
338 protected struct ConstructingHandle
339 {
340 public ConstructingHandle(IntPtr h)
341 {
342 NativeHandle = h;
343 }
344
345 public IntPtr NativeHandle { get; set; }
346 }
347
348 public abstract class NativeMethods : Efl.Eo.NativeClass
349 {
350 private static EflConstructorSelegate csharpEflConstructorStaticDelegate = new EflConstructorSelegate(Constructor);
351 private static Efl.Eo.NativeModule EoModule = new Efl.Eo.NativeModule("eo");
352
353 private delegate IntPtr EflConstructorSelegate(IntPtr obj, IntPtr pd);
354
355 public override System.Collections.Generic.List<Efl_Op_Description> GetEoOps(Type type)
356 {
357 var descs = new System.Collections.Generic.List<Efl_Op_Description>();
358
359 descs.Add(new Efl_Op_Description()
360 {
361 api_func = Efl.Eo.FunctionInterop.LoadFunctionPointer(EoModule.Module, "efl_constructor"),
362 func = Marshal.GetFunctionPointerForDelegate(csharpEflConstructorStaticDelegate)
363 });
364
365 return descs;
366 }
367
368 private static IntPtr Constructor(IntPtr obj, IntPtr pd)
369 {
370 try
371 {
372 var eoKlass = Efl.Eo.Globals.efl_class_get(obj);
373 var managedType = ClassRegister.GetManagedType(eoKlass);
374 if (managedType == null)
375 {
376 IntPtr nativeName = Efl.Eo.Globals.efl_class_name_get(eoKlass);
377 var name = Eina.StringConversion.NativeUtf8ToManagedString(nativeName);
378 Eina.Log.Warning($"Can't get Managed class for object handle 0x{(UInt64)obj:x} with native class [{name}]");
379 return IntPtr.Zero;
380 }
381
382 var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
383 ConstructorInfo constructor = managedType.GetConstructor(flags, null, new Type[1] { typeof(ConstructingHandle) }, null);
384 var eoWrapper = (Efl.Eo.IWrapper) constructor.Invoke(new object[1] { new ConstructingHandle(obj) });
385 if (eoWrapper == null)
386 {
387 Eina.Log.Warning("Constructor was unable to create a new object");
388 return IntPtr.Zero;
389 }
390
391 return eoWrapper.NativeHandle;
392 }
393 catch (Exception e)
394 {
395 Eina.Log.Warning($"Inherited constructor error: {e.ToString()}");
396 Eina.Error.Set(Eina.Error.UNHANDLED_EXCEPTION);
397 return IntPtr.Zero;
398 }
399 }
400 }
300} 401}
301 402
302} // namespace Global 403} // namespace Eo
303 404
304} // namespace Efl 405} // namespace Efl
diff --git a/src/bindings/mono/eo_mono/iwrapper.cs b/src/bindings/mono/eo_mono/iwrapper.cs
index 9e73ca4687..618d16ca0f 100644
--- a/src/bindings/mono/eo_mono/iwrapper.cs
+++ b/src/bindings/mono/eo_mono/iwrapper.cs
@@ -44,10 +44,6 @@ public class Globals
44 public static FunctionWrapper<efl_object_shutdown_delegate> efl_object_shutdown_ptr = new FunctionWrapper<efl_object_shutdown_delegate>(efl.Libs.EoModule, "efl_object_shutdown"); 44 public static FunctionWrapper<efl_object_shutdown_delegate> efl_object_shutdown_ptr = new FunctionWrapper<efl_object_shutdown_delegate>(efl.Libs.EoModule, "efl_object_shutdown");
45 public static void efl_object_shutdown() => efl_object_shutdown_ptr.Value.Delegate(); 45 public static void efl_object_shutdown() => efl_object_shutdown_ptr.Value.Delegate();
46 // [DllImport(efl.Libs.Eo)] public static extern void efl_object_shutdown(); 46 // [DllImport(efl.Libs.Eo)] public static extern void efl_object_shutdown();
47 public static FunctionWrapper<_efl_add_internal_start_delegate> _efl_add_internal_start_ptr = new FunctionWrapper<_efl_add_internal_start_delegate>(efl.Libs.EoModule, "_efl_add_internal_start");
48 public delegate IntPtr
49 _efl_add_internal_start_delegate([MarshalAs(UnmanagedType.LPStr)] String file, int line,
50 IntPtr klass, IntPtr parent, byte is_ref, byte is_fallback);
51 47
52 [DllImport(efl.Libs.CustomExports)] public static extern IntPtr efl_mono_wrapper_supervisor_get(IntPtr eo); 48 [DllImport(efl.Libs.CustomExports)] public static extern IntPtr efl_mono_wrapper_supervisor_get(IntPtr eo);
53 [DllImport(efl.Libs.CustomExports)] public static extern void efl_mono_wrapper_supervisor_set(IntPtr eo, IntPtr ws); 49 [DllImport(efl.Libs.CustomExports)] public static extern void efl_mono_wrapper_supervisor_set(IntPtr eo, IntPtr ws);
@@ -55,6 +51,9 @@ public class Globals
55 [DllImport(efl.Libs.Eo)] public static extern IntPtr 51 [DllImport(efl.Libs.Eo)] public static extern IntPtr
56 _efl_add_internal_start([MarshalAs(UnmanagedType.LPStr)] String file, int line, 52 _efl_add_internal_start([MarshalAs(UnmanagedType.LPStr)] String file, int line,
57 IntPtr klass, IntPtr parent, byte is_ref, byte is_fallback); 53 IntPtr klass, IntPtr parent, byte is_ref, byte is_fallback);
54 [DllImport(efl.Libs.Eo)] public static extern IntPtr
55 _efl_add_internal_start_bindings([MarshalAs(UnmanagedType.LPStr)] String file, int line, IntPtr klass, IntPtr parent,
56 byte is_ref, byte is_fallback, IntPtr substitute_ctor, IntPtr data);
58 public delegate IntPtr 57 public delegate IntPtr
59 _efl_add_end_delegate(IntPtr eo, byte is_ref, byte is_fallback); 58 _efl_add_end_delegate(IntPtr eo, byte is_ref, byte is_fallback);
60 [DllImport(efl.Libs.Eo)] public static extern IntPtr 59 [DllImport(efl.Libs.Eo)] public static extern IntPtr
@@ -196,6 +195,10 @@ public class Globals
196 public delegate IntPtr dlerror_delegate(); 195 public delegate IntPtr dlerror_delegate();
197 [DllImport(efl.Libs.Evil)] public static extern IntPtr dlerror(); 196 [DllImport(efl.Libs.Evil)] public static extern IntPtr dlerror();
198 197
198 [DllImport(efl.Libs.Eo)] public static extern IntPtr efl_constructor(IntPtr obj);
199
200 [DllImport(efl.Libs.CustomExports)] public static extern IntPtr efl_mono_avoid_top_level_constructor_callback_addr_get();
201
199 [DllImport(efl.Libs.Eo)] [return: MarshalAs(UnmanagedType.U1)] public static extern bool 202 [DllImport(efl.Libs.Eo)] [return: MarshalAs(UnmanagedType.U1)] public static extern bool
200 efl_event_callback_priority_add(IntPtr obj, IntPtr desc, short priority, IntPtr cb, IntPtr data); 203 efl_event_callback_priority_add(IntPtr obj, IntPtr desc, short priority, IntPtr cb, IntPtr data);
201 204
diff --git a/src/lib/efl_mono/efl_custom_exports_mono.c b/src/lib/efl_mono/efl_custom_exports_mono.c
index 55f0054da0..a11a11e4b6 100644
--- a/src/lib/efl_mono/efl_custom_exports_mono.c
+++ b/src/lib/efl_mono/efl_custom_exports_mono.c
@@ -166,6 +166,16 @@ EAPI Eina_Free_Cb efl_mono_native_efl_unref_addr_get()
166 return (Eina_Free_Cb)efl_mono_thread_safe_efl_unref; 166 return (Eina_Free_Cb)efl_mono_thread_safe_efl_unref;
167} 167}
168 168
169static Eo *_efl_mono_avoid_top_level_constructor_cb(void *data EINA_UNUSED, Eo *obj)
170{
171 return efl_constructor(efl_super(obj, efl_class_get(obj)));
172}
173
174EAPI Efl_Substitute_Ctor_Cb efl_mono_avoid_top_level_constructor_callback_addr_get()
175{
176 return &_efl_mono_avoid_top_level_constructor_cb;
177}
178
169// Iterator Wrapper // 179// Iterator Wrapper //
170 180
171typedef struct _Eina_Iterator_Wrapper_Mono 181typedef struct _Eina_Iterator_Wrapper_Mono
diff --git a/src/tests/efl_mono/EoConstruction.cs b/src/tests/efl_mono/EoConstruction.cs
new file mode 100644
index 0000000000..cd4a774bd1
--- /dev/null
+++ b/src/tests/efl_mono/EoConstruction.cs
@@ -0,0 +1,79 @@
1using System;
2
3class InheritedConstructibleObject : Dummy.ConstructibleObject
4{
5 public InheritedConstructibleObject()
6 {
7 if (this.NativeConstructionCount != 1)
8 {
9 DefaultConstrutorCallCount = -100;
10 }
11
12 ++DefaultConstrutorCallCount;
13 this.IncrementDefaultConstructionCount();
14 }
15
16 private InheritedConstructibleObject(ConstructingHandle ch) : base(ch)
17 {
18 if (this.NativeConstructionCount != 1)
19 {
20 SpecialConstrutorCallCount = -100;
21 }
22
23 ++SpecialConstrutorCallCount;
24 this.IncrementSpecialConstructionCount();
25 }
26
27 public int DefaultConstrutorCallCount { get; set; } = 0;
28 public int SpecialConstrutorCallCount { get; set; } = 0;
29}
30
31namespace TestSuite
32{
33
34class TestEoConstruction
35{
36 public static void TestGeneratedEoDirectConstruction()
37 {
38 var obj = new Dummy.ConstructibleObject();
39 Test.AssertEquals(obj.NativeConstructionCount, 1);
40 Test.AssertEquals(obj.DefaultConstructionCount, 0);
41 Test.AssertEquals(obj.SpecialConstructionCount, 0);
42 obj.Dispose();
43 }
44
45 public static void TestInheritedEoDirectConstruction()
46 {
47 var obj = new InheritedConstructibleObject();
48 Test.AssertEquals(obj.NativeConstructionCount, 1);
49 Test.AssertEquals(obj.DefaultConstructionCount, 1);
50 Test.AssertEquals(obj.SpecialConstructionCount, 0);
51 Test.AssertEquals(obj.DefaultConstrutorCallCount, 1);
52 Test.AssertEquals(obj.SpecialConstrutorCallCount, 0);
53 obj.Dispose();
54 }
55
56 public static void TestInheritedEoIndirectConstruction()
57 {
58 var obj = new Dummy.ConstructibleObject();
59 Test.AssertEquals(obj.NativeConstructionCount, 1);
60 Test.AssertEquals(obj.DefaultConstructionCount, 0);
61 Test.AssertEquals(obj.SpecialConstructionCount, 0);
62
63 var obj2 = (InheritedConstructibleObject) obj.ConstructTypeAndStore(typeof(InheritedConstructibleObject));
64 Test.AssertEquals(obj2.NativeConstructionCount, 1);
65 Test.AssertEquals(obj2.DefaultConstructionCount, 0);
66 Test.AssertEquals(obj2.SpecialConstructionCount, 1);
67 Test.AssertEquals(obj2.DefaultConstrutorCallCount, 0);
68 Test.AssertEquals(obj2.SpecialConstrutorCallCount, 1);
69
70 var internalObj = obj.InternalObject;
71 Test.Assert(obj2 == internalObj); // Ensure it always use the same object instance
72 Test.AssertEquals(obj2.NativeConstructionCount, 1); // And that constructors are not called again
73
74 obj.Dispose();
75 obj2.Dispose();
76 }
77}
78
79}
diff --git a/src/tests/efl_mono/dummy_constructible_object.c b/src/tests/efl_mono/dummy_constructible_object.c
new file mode 100644
index 0000000000..96842709ba
--- /dev/null
+++ b/src/tests/efl_mono/dummy_constructible_object.c
@@ -0,0 +1,70 @@
1#include "libefl_mono_native_test.h"
2
3typedef struct _Dummy_Constructible_Object_Data
4{
5 Eo *internal_obj;
6 int native_construction_count;
7 int default_construction_count;
8 int special_construction_count;
9} Dummy_Constructible_Object_Data;
10
11
12EOLIAN static Eo *
13_dummy_constructible_object_efl_object_constructor(Eo *obj, Dummy_Constructible_Object_Data *pd)
14{
15 ++(pd->native_construction_count);
16 return efl_constructor(efl_super(obj, DUMMY_CONSTRUCTIBLE_OBJECT_CLASS));
17}
18
19EOLIAN static void
20_dummy_constructible_object_efl_object_destructor(Eo *obj, Dummy_Constructible_Object_Data *pd)
21{
22 if (pd->internal_obj)
23 efl_unref(pd->internal_obj);
24 efl_destructor(efl_super(obj, DUMMY_CONSTRUCTIBLE_OBJECT_CLASS));
25}
26
27EOLIAN static Efl_Object *
28_dummy_constructible_object_construct_type_and_store(Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd, const Efl_Class *klass)
29{
30 pd->internal_obj = efl_add_ref(klass, NULL);
31 return pd->internal_obj;
32}
33
34EOLIAN static void
35_dummy_constructible_object_increment_default_construction_count(Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
36{
37 ++(pd->default_construction_count);
38}
39
40EOLIAN static void
41_dummy_constructible_object_increment_special_construction_count(Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
42{
43 ++(pd->special_construction_count);
44}
45
46EOLIAN static int
47_dummy_constructible_object_native_construction_count_get(const Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
48{
49 return pd->native_construction_count;
50}
51
52EOLIAN static int
53_dummy_constructible_object_default_construction_count_get(const Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
54{
55 return pd->default_construction_count;
56}
57
58EOLIAN static int
59_dummy_constructible_object_special_construction_count_get(const Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
60{
61 return pd->special_construction_count;
62}
63
64EOLIAN static Efl_Object *
65_dummy_constructible_object_internal_object_get(const Eo *obj EINA_UNUSED, Dummy_Constructible_Object_Data *pd)
66{
67 return pd->internal_obj;
68}
69
70#include "dummy_constructible_object.eo.c"
diff --git a/src/tests/efl_mono/dummy_constructible_object.eo b/src/tests/efl_mono/dummy_constructible_object.eo
new file mode 100644
index 0000000000..f8ae944e6c
--- /dev/null
+++ b/src/tests/efl_mono/dummy_constructible_object.eo
@@ -0,0 +1,47 @@
1class Dummy.Constructible_Object extends Efl.Object {
2 methods {
3 construct_type_and_store {
4 params {
5 @in type: const(Efl.Class);
6 }
7 return: Efl.Object;
8 }
9 increment_default_construction_count {
10 }
11 increment_special_construction_count {
12 }
13 @property native_construction_count {
14 get {
15 }
16 values {
17 value: int;
18 }
19 }
20 @property default_construction_count {
21 get {
22 }
23 values {
24 value: int;
25 }
26 }
27 @property special_construction_count {
28 get {
29 }
30 values {
31 value: int;
32 }
33 }
34 @property internal_object {
35 get {
36 }
37 values {
38 value: Efl.Object;
39 }
40 }
41 }
42 implements {
43 Efl.Object.constructor;
44 Efl.Object.destructor;
45 }
46}
47
diff --git a/src/tests/efl_mono/dummy_test_object.c b/src/tests/efl_mono/dummy_test_object.c
index fa5d01888a..f9b276c085 100644
--- a/src/tests/efl_mono/dummy_test_object.c
+++ b/src/tests/efl_mono/dummy_test_object.c
@@ -56,9 +56,9 @@ Dummy_Numberwrapper **_new_obj_ref(int n)
56 return &r; 56 return &r;
57} 57}
58 58
59// ############ // 59// ################# //
60// Test.Testing // 60// Dummy.Test_Object //
61// ############ // 61// ################# //
62 62
63static Efl_Object* 63static Efl_Object*
64_dummy_test_object_efl_object_constructor(Eo *obj, Dummy_Test_Object_Data *pd) 64_dummy_test_object_efl_object_constructor(Eo *obj, Dummy_Test_Object_Data *pd)
diff --git a/src/tests/efl_mono/libefl_mono_native_test.h b/src/tests/efl_mono/libefl_mono_native_test.h
index 9251118fc6..b726bd05c1 100644
--- a/src/tests/efl_mono/libefl_mono_native_test.h
+++ b/src/tests/efl_mono/libefl_mono_native_test.h
@@ -55,6 +55,7 @@
55#include "dummy_inherit_helper.eo.h" 55#include "dummy_inherit_helper.eo.h"
56#include "dummy_part_holder.eo.h" 56#include "dummy_part_holder.eo.h"
57#include "dummy_event_manager.eo.h" 57#include "dummy_event_manager.eo.h"
58#include "dummy_constructible_object.eo.h"
58 59
59#include <interfaces/efl_part.eo.h> 60#include <interfaces/efl_part.eo.h>
60 61
diff --git a/src/tests/efl_mono/meson.build b/src/tests/efl_mono/meson.build
index f75a5b8bb9..e464cdd2a8 100644
--- a/src/tests/efl_mono/meson.build
+++ b/src/tests/efl_mono/meson.build
@@ -7,6 +7,7 @@ eo_files = [
7 'dummy_inherit_iface.eo', 7 'dummy_inherit_iface.eo',
8 'dummy_part_holder.eo', 8 'dummy_part_holder.eo',
9 'dummy_event_manager.eo', 9 'dummy_event_manager.eo',
10 'dummy_constructible_object.eo',
10] 11]
11 12
12eo_file_targets = [] 13eo_file_targets = []
@@ -33,6 +34,7 @@ efl_mono_native_test = library('efl_mono_native_test',
33 'dummy_part_holder.c', 34 'dummy_part_holder.c',
34 'dummy_test_object.c', 35 'dummy_test_object.c',
35 'dummy_event_manager.c', 36 'dummy_event_manager.c',
37 'dummy_constructible_object.c',
36 ], 38 ],
37 dependencies : [ecore, eo, efl], 39 dependencies : [ecore, eo, efl],
38) 40)
@@ -65,6 +67,7 @@ efl_mono_src = [
65 'Eldbus.cs', 67 'Eldbus.cs',
66 'Eo.cs', 68 'Eo.cs',
67 'EoPromises.cs', 69 'EoPromises.cs',
70 'EoConstruction.cs',
68 'Errors.cs', 71 'Errors.cs',
69 'Events.cs', 72 'Events.cs',
70 'FunctionPointers.cs', 73 'FunctionPointers.cs',