summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLauro Moura <lauromoura@expertisesolutions.com.br>2019-02-06 17:50:28 -0200
committerVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-03-01 23:04:08 -0300
commitdd89eb2fd1755c2816d97f28822639e03ed38608 (patch)
tree9931650c7db8f267e88b87103fe1c9cc85e0d594
parent6d61ca915195a5ff4c5dc24c271d37fa22d64314 (diff)
efl-mono: Add support for Efl.Class
Efl.Class (in practice, the return from the *_class_get() functions) can be used as argument to functions, like in Efl.Object.provider_find and Efl.Ui.Widget_Factory.item_class(get/set). This commits adds support by representing Efl.Class instances as System.Type in the C# API, allowing someone to do things like: `factory.ItemClass == typeof(MyFramework.MyButton)` It also supports user-defined classes that inherit from efl classes.
-rw-r--r--src/bin/eolian_mono/eolian/mono/klass.hh29
-rw-r--r--src/bin/eolian_mono/eolian/mono/marshall_annotation.hh44
-rw-r--r--src/bin/eolian_mono/eolian/mono/type_impl.hh3
-rw-r--r--src/bindings/mono/eina_mono/eina_container_common.cs16
-rw-r--r--src/bindings/mono/eo_mono/iwrapper.cs159
-rw-r--r--src/bindings/mono/meson.build1
-rw-r--r--src/tests/efl_mono/Eo.cs13
-rw-r--r--src/tests/efl_mono/dummy_test_object.eo1
-rw-r--r--src/tests/efl_mono/libefl_mono_native_test.c12
9 files changed, 234 insertions, 44 deletions
diff --git a/src/bin/eolian_mono/eolian/mono/klass.hh b/src/bin/eolian_mono/eolian/mono/klass.hh
index 6c02de6..e70729b 100644
--- a/src/bin/eolian_mono/eolian/mono/klass.hh
+++ b/src/bin/eolian_mono/eolian/mono/klass.hh
@@ -347,6 +347,15 @@ struct klass
347 return false; 347 return false;
348 } 348 }
349 349
350 // Copied from nativeinherit class, used when setting up providers.
351 if(!as_generator(
352 scope_tab << "private static " << (root ? "" : "new ") << " IntPtr GetEflClassStatic()\n"
353 << scope_tab << "{\n"
354 << scope_tab << scope_tab << "return " << name_helpers::klass_get_full_name(cls) << "();\n"
355 << scope_tab << "}\n"
356 ).generate(sink, attributes::unused, inherit_cxt))
357 return false;
358
350 if(!as_generator("}\n").generate(sink, attributes::unused, inherit_cxt)) return false; 359 if(!as_generator("}\n").generate(sink, attributes::unused, inherit_cxt)) return false;
351 } 360 }
352 361
@@ -454,7 +463,7 @@ struct klass
454 << scope_tab << scope_tab << scope_tab << "if (((object)this).GetType() == typeof (" << inherit_name << "))\n" 463 << scope_tab << scope_tab << scope_tab << "if (((object)this).GetType() == typeof (" << inherit_name << "))\n"
455 << scope_tab << scope_tab << scope_tab << scope_tab << "return " << native_inherit_full_name << ".GetEflClassStatic();\n" 464 << scope_tab << scope_tab << scope_tab << scope_tab << "return " << native_inherit_full_name << ".GetEflClassStatic();\n"
456 << scope_tab << scope_tab << scope_tab << "else\n" 465 << scope_tab << scope_tab << scope_tab << "else\n"
457 << scope_tab << scope_tab << scope_tab << scope_tab << "return Efl.Eo.Globals.klasses[((object)this).GetType()];\n" 466 << scope_tab << scope_tab << scope_tab << scope_tab << "return Efl.Eo.ClassRegister.klassFromType[((object)this).GetType()];\n"
458 << scope_tab << scope_tab << "}\n" 467 << scope_tab << scope_tab << "}\n"
459 << scope_tab << "}\n" 468 << scope_tab << "}\n"
460 ).generate(sink, attributes::unused, context)) 469 ).generate(sink, attributes::unused, context))
@@ -512,7 +521,7 @@ struct klass
512 // For constructors with arguments, the parent is also required, as optional parameters can't come before non-optional paramenters. 521 // For constructors with arguments, the parent is also required, as optional parameters can't come before non-optional paramenters.
513 << scope_tab << "public " << inherit_name << "(Efl.Object parent" << ((constructors.size() > 0) ? "" : "= null") << "\n" 522 << scope_tab << "public " << inherit_name << "(Efl.Object parent" << ((constructors.size() > 0) ? "" : "= null") << "\n"
514 << scope_tab << scope_tab << scope_tab << *(", " << constructor_param ) << ") :\n" 523 << scope_tab << scope_tab << scope_tab << *(", " << constructor_param ) << ") :\n"
515 << scope_tab << scope_tab << (root ? "this" : "base") << "(\"" << inherit_name << "\", " << name_helpers::klass_get_name(cls) << "(), typeof(" << inherit_name << "), parent)\n" 524 << scope_tab << scope_tab << (root ? "this" : "base") << "(" << name_helpers::klass_get_name(cls) << "(), typeof(" << inherit_name << "), parent)\n"
516 << scope_tab << "{\n" 525 << scope_tab << "{\n"
517 << *(scope_tab << scope_tab << constructor_invocation << "\n" ) 526 << *(scope_tab << scope_tab << constructor_invocation << "\n" )
518 << scope_tab << scope_tab << "FinishInstantiation();\n" 527 << scope_tab << scope_tab << "FinishInstantiation();\n"
@@ -531,7 +540,7 @@ struct klass
531 { 540 {
532 return as_generator( 541 return as_generator(
533 scope_tab << "///<summary>Internal usage: Constructor to forward the wrapper initialization to the root class that interfaces with native code. Should not be used directly.</summary>\n" 542 scope_tab << "///<summary>Internal usage: Constructor to forward the wrapper initialization to the root class that interfaces with native code. Should not be used directly.</summary>\n"
534 << scope_tab << "protected " << inherit_name << "(String klass_name, IntPtr base_klass, System.Type managed_type, Efl.Object parent) : base(klass_name, base_klass, managed_type, parent) {}\n" 543 << scope_tab << "protected " << inherit_name << "(IntPtr base_klass, System.Type managed_type, Efl.Object parent) : base(base_klass, managed_type, parent) {}\n"
535 ).generate(sink, attributes::unused, context); 544 ).generate(sink, attributes::unused, context);
536 545
537 } 546 }
@@ -539,22 +548,12 @@ struct klass
539 // Detailed constructors go only in root classes. 548 // Detailed constructors go only in root classes.
540 return as_generator( 549 return as_generator(
541 /// Actual root costructor that creates class and instantiates 550 /// Actual root costructor that creates class and instantiates
542 scope_tab << "protected " << inherit_name << "(String klass_name, IntPtr base_klass, System.Type managed_type, Efl.Object parent)\n" 551 scope_tab << "protected " << inherit_name << "(IntPtr base_klass, System.Type managed_type, Efl.Object parent)\n"
543 << scope_tab << "{\n" 552 << scope_tab << "{\n"
544 << scope_tab << scope_tab << "inherited = ((object)this).GetType() != managed_type;\n" 553 << scope_tab << scope_tab << "inherited = ((object)this).GetType() != managed_type;\n"
545 << scope_tab << scope_tab << "IntPtr actual_klass = base_klass;\n" 554 << scope_tab << scope_tab << "IntPtr actual_klass = base_klass;\n"
546 << scope_tab << scope_tab << "if (inherited) {\n" 555 << scope_tab << scope_tab << "if (inherited) {\n"
547 << scope_tab << scope_tab << scope_tab << "if (!Efl.Eo.Globals.klasses.ContainsKey(((object)this).GetType())) {\n" 556 << scope_tab << scope_tab << scope_tab << "actual_klass = Efl.Eo.ClassRegister.GetInheritKlassOrRegister(base_klass, ((object)this).GetType());\n"
548 << scope_tab << scope_tab << scope_tab << scope_tab << "lock (klassAllocLock) {\n"
549 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "actual_klass = Efl.Eo.Globals.register_class(klass_name, base_klass, ((object)this).GetType());\n"
550 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "if (actual_klass == System.IntPtr.Zero) {\n"
551 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "throw new System.InvalidOperationException(\"Failed to initialize class '" << inherit_name << "'\");\n"
552 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "}\n"
553 << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.klasses[((object)this).GetType()] = actual_klass;\n"
554 << scope_tab << scope_tab << scope_tab << scope_tab << "}\n"
555 << scope_tab << scope_tab << scope_tab << "}\n"
556 << scope_tab << scope_tab << scope_tab << "else\n"
557 << scope_tab << scope_tab << scope_tab << scope_tab << "actual_klass = Efl.Eo.Globals.klasses[((object)this).GetType()];\n"
558 << scope_tab << scope_tab << "}\n" 557 << scope_tab << scope_tab << "}\n"
559 << scope_tab << scope_tab << "handle = Efl.Eo.Globals.instantiate_start(actual_klass, parent);\n" 558 << scope_tab << scope_tab << "handle = Efl.Eo.Globals.instantiate_start(actual_klass, parent);\n"
560 << scope_tab << scope_tab << "register_event_proxies();\n" 559 << scope_tab << scope_tab << "register_event_proxies();\n"
diff --git a/src/bin/eolian_mono/eolian/mono/marshall_annotation.hh b/src/bin/eolian_mono/eolian/mono/marshall_annotation.hh
index 6ddb990..744b4f8 100644
--- a/src/bin/eolian_mono/eolian/mono/marshall_annotation.hh
+++ b/src/bin/eolian_mono/eolian/mono/marshall_annotation.hh
@@ -142,12 +142,22 @@ struct marshall_annotation_visitor_generate
142 } 142 }
143 bool operator()(attributes::klass_name const& klass_name) const 143 bool operator()(attributes::klass_name const& klass_name) const
144 { 144 {
145 const char no_return_prefix[] = "[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Efl.Eo.MarshalTest<"; 145 const char *return_prefix = is_return ? "return:" : "";
146 const char return_prefix[] = "[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Efl.Eo.MarshalTest<"; 146 const char *marshal_prefix = "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(";
147 return as_generator 147
148 ((is_return ? return_prefix : no_return_prefix) 148 std::string name = name_helpers::klass_full_concrete_name(klass_name);
149 << string << ", Efl.Eo." << (klass_name.base_qualifier & qualifier_info::is_own ? "OwnTag" : "NonOwnTag") << ">))]" 149
150 ).generate(sink, name_helpers::klass_full_concrete_name(klass_name), *context); 150 if (name == "Efl.Class")
151 name = "Efl.Eo.MarshalEflClass";
152 else
153 {
154 auto own = klass_name.base_qualifier & qualifier_info::is_own ? "OwnTag" : "NonOwnTag";
155 name = "Efl.Eo.MarshalTest<" + name + ", Efl.Eo." + own + ">";
156 }
157
158 return as_generator(
159 lit("[") << return_prefix << marshal_prefix << name << "))]"
160 ).generate(sink, name, *context);
151 } 161 }
152 bool operator()(attributes::complex_type_def const& c) const 162 bool operator()(attributes::complex_type_def const& c) const
153 { 163 {
@@ -252,12 +262,22 @@ struct marshall_native_annotation_visitor_generate
252 } 262 }
253 bool operator()(attributes::klass_name const& klass_name) const 263 bool operator()(attributes::klass_name const& klass_name) const
254 { 264 {
255 const char no_return_prefix[] = "[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Efl.Eo.MarshalTest<"; 265 const char *return_prefix = is_return ? "return:" : "";
256 const char return_prefix[] = "[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Efl.Eo.MarshalTest<"; 266 const char *marshal_prefix = "MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(";
257 return as_generator 267
258 ((is_return ? return_prefix : no_return_prefix) 268 std::string name = name_helpers::klass_full_concrete_name(klass_name);
259 << string << ", Efl.Eo." << (klass_name.base_qualifier & qualifier_info::is_own ? "OwnTag" : "NonOwnTag") << ">))]" 269
260 ).generate(sink, name_helpers::klass_full_concrete_name(klass_name), *context); 270 if (name == "Efl.Class")
271 name = "Efl.Eo.MarshalEflClass";
272 else
273 {
274 auto own = klass_name.base_qualifier & qualifier_info::is_own ? "OwnTag" : "NonOwnTag";
275 name = "Efl.Eo.MarshalTest<" + name + ", Efl.Eo." + own + ">";
276 }
277
278 return as_generator(
279 lit("[") << return_prefix << marshal_prefix << name << "))]"
280 ).generate(sink, name, *context);
261 } 281 }
262 bool operator()(attributes::complex_type_def const& c) const 282 bool operator()(attributes::complex_type_def const& c) const
263 { 283 {
diff --git a/src/bin/eolian_mono/eolian/mono/type_impl.hh b/src/bin/eolian_mono/eolian/mono/type_impl.hh
index 9810250..f34c479 100644
--- a/src/bin/eolian_mono/eolian/mono/type_impl.hh
+++ b/src/bin/eolian_mono/eolian/mono/type_impl.hh
@@ -309,6 +309,9 @@ struct visitor_generate
309 } 309 }
310 bool operator()(attributes::klass_name klass) const 310 bool operator()(attributes::klass_name klass) const
311 { 311 {
312 // Efl.Class is manually handled in a custom marshall to be represented by a System.Type.
313 if (name_helpers::klass_full_concrete_name(klass) == "Efl.Class")
314 return as_generator(lit("Type")).generate(sink, attributes::unused, *context);
312 if(klass.type == attributes::class_type::regular || klass.type == attributes::class_type::abstract_) 315 if(klass.type == attributes::class_type::regular || klass.type == attributes::class_type::abstract_)
313 return as_generator(string).generate(sink, name_helpers::klass_full_concrete_name(klass), *context); 316 return as_generator(string).generate(sink, name_helpers::klass_full_concrete_name(klass), *context);
314 else 317 else
diff --git a/src/bindings/mono/eina_mono/eina_container_common.cs b/src/bindings/mono/eina_mono/eina_container_common.cs
index 838a7ed..bc2ce84 100644
--- a/src/bindings/mono/eina_mono/eina_container_common.cs
+++ b/src/bindings/mono/eina_mono/eina_container_common.cs
@@ -530,23 +530,11 @@ public static class TraitFunctions
530 530
531 if (type.IsInterface) 531 if (type.IsInterface)
532 { 532 {
533 string[] names = type.FullName.Split('.'); 533 string fullName = type.FullName + "Concrete";
534 names[names.Count() - 1] = names.Last().Substring(1); // Remove the leading 'I' (What about user-defined interfaces?)
535
536 string fullName = string.Join(".", names);
537 return type.Assembly.GetType(fullName); // That was our best guess... 534 return type.Assembly.GetType(fullName); // That was our best guess...
538 } 535 }
539 536
540 537 return type; // Not interface, so it should be a concrete.
541 System.Type current = type;
542 while (current != null)
543 {
544 if (current.Name.EndsWith("Inherit"))
545 throw new Exception("Inherit-based classes are not currently supported.");
546 current = current.BaseType;
547 }
548
549 return type; // Not inherited neither interface, so it should be a concrete.
550 } 538 }
551 539
552 public static object RegisterTypeTraits<T>() 540 public static object RegisterTypeTraits<T>()
diff --git a/src/bindings/mono/eo_mono/iwrapper.cs b/src/bindings/mono/eo_mono/iwrapper.cs
index 16acf6a..5388116 100644
--- a/src/bindings/mono/eo_mono/iwrapper.cs
+++ b/src/bindings/mono/eo_mono/iwrapper.cs
@@ -26,6 +26,8 @@ public class Globals {
26 [DllImport(efl.Libs.Eo)] public static extern int 26 [DllImport(efl.Libs.Eo)] public static extern int
27 efl_ref_count(IntPtr eo); 27 efl_ref_count(IntPtr eo);
28 [DllImport(efl.Libs.Eo)] public static extern IntPtr 28 [DllImport(efl.Libs.Eo)] public static extern IntPtr
29 efl_class_name_get(IntPtr eo);
30 [DllImport(efl.Libs.Eo)] public static extern IntPtr
29 efl_class_new(IntPtr class_description, IntPtr parent, IntPtr term); 31 efl_class_new(IntPtr class_description, IntPtr parent, IntPtr term);
30 [DllImport(efl.Libs.Eo)] public static extern IntPtr 32 [DllImport(efl.Libs.Eo)] public static extern IntPtr
31 efl_class_new(IntPtr class_description, IntPtr parent, IntPtr extn1, IntPtr term); 33 efl_class_new(IntPtr class_description, IntPtr parent, IntPtr extn1, IntPtr term);
@@ -150,9 +152,6 @@ public class Globals {
150 [DllImport(efl.Libs.Eo)] public static extern IntPtr 152 [DllImport(efl.Libs.Eo)] public static extern IntPtr
151 efl_object_legacy_only_event_description_get([MarshalAs(UnmanagedType.LPStr)] String name); 153 efl_object_legacy_only_event_description_get([MarshalAs(UnmanagedType.LPStr)] String name);
152 154
153 public static System.Collections.Concurrent.ConcurrentDictionary<System.Type, System.IntPtr> klasses
154 = new System.Collections.Concurrent.ConcurrentDictionary<System.Type, System.IntPtr>();
155
156 public const int RTLD_NOW = 2; 155 public const int RTLD_NOW = 2;
157 156
158 public delegate byte class_initializer(IntPtr klass); 157 public delegate byte class_initializer(IntPtr klass);
@@ -529,6 +528,120 @@ public interface IWrapper
529 } 528 }
530} 529}
531 530
531public static class ClassRegister
532{
533 public static System.Type GetManagedType(IntPtr klass)
534 {
535 System.Type t;
536 if (Efl.Eo.ClassRegister.typeFromKlass.TryGetValue(klass, out t))
537 return t;
538
539 // If it isn't on the dictionary then it is a Native binding class
540 IntPtr namePtr = Efl.Eo.Globals.efl_class_name_get(klass);
541 if (namePtr == IntPtr.Zero) {
542 throw new System.InvalidOperationException($"Could not get Native class name. Handle: {klass}");
543 }
544
545 string name = Eina.StringConversion.NativeUtf8ToManagedString(namePtr)
546 .Replace("_", ""); // Convert Efl C name to C# name
547
548 var curr_asm = typeof(IWrapper).Assembly;
549 t = curr_asm.GetType(name);
550 if (t == null)
551 {
552 foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
553 {
554 if (assembly == curr_asm)
555 continue;
556
557 t = assembly.GetType(name);
558 if (t != null)
559 break;
560 }
561 if (t == null) {
562 throw new System.InvalidOperationException($"Could not find the C# binding class for the EFL class: {name}");
563 }
564 }
565 AddToKlassTypeBiDictionary(klass, t); // Cache it in the dictionary
566 return t;
567 }
568
569 public static IntPtr GetKlass(System.Type objectType)
570 {
571 IntPtr klass;
572 if (klassFromType.TryGetValue(objectType, out klass))
573 return klass;
574
575 // Check if it is a Native binding class
576 klass = GetNativeKlassPtr(objectType);
577 if (klass != IntPtr.Zero) {
578 // Add to the dictionary cache
579 AddToKlassTypeBiDictionary(klass, objectType);
580 return klass;
581 }
582
583 // Unregistered Inherited class, let's register it
584 IntPtr baseKlass = GetNativeBaseKlassPtr(objectType);
585 if (baseKlass == IntPtr.Zero)
586 throw new System.InvalidOperationException($"Could not get base C# binding class for Inherited type: {objectType.FullName}");
587 return RegisterKlass(baseKlass, objectType);
588 }
589
590 public static IntPtr GetInheritKlassOrRegister(IntPtr baseKlass, System.Type objectType)
591 {
592 IntPtr klass;
593 if (klassFromType.TryGetValue(objectType, out klass))
594 return klass;
595
596 return RegisterKlass(baseKlass, objectType);
597 }
598
599 private static IntPtr RegisterKlass(IntPtr baseKlass, System.Type objectType)
600 {
601 lock (klassAllocLock) {
602 IntPtr newKlass = Efl.Eo.Globals.register_class(objectType.FullName, baseKlass, objectType);
603 if (newKlass == IntPtr.Zero) {
604 throw new System.InvalidOperationException($"Failed to register class '{objectType.FullName}'");
605 }
606 AddToKlassTypeBiDictionary(newKlass, objectType);
607 return newKlass;
608 }
609 }
610
611 private static IntPtr GetNativeBaseKlassPtr(System.Type objectType)
612 {
613 for (System.Type t = objectType.BaseType; t != null; t = t.BaseType)
614 {
615 var method = t.GetMethod("GetEflClassStatic",
616 System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
617 if (method != null)
618 return (IntPtr) method.Invoke(null, null);
619 }
620 throw new System.InvalidOperationException($"Class '{objectType.FullName}' is not an Efl object");
621 }
622
623 private static IntPtr GetNativeKlassPtr(System.Type objectType)
624 {
625 var method = objectType.GetMethod("GetEflClassStatic",
626 System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
627 return (IntPtr) method?.Invoke(null, null);
628 }
629
630 public static void AddToKlassTypeBiDictionary(IntPtr klassPtr, System.Type objectType)
631 {
632 klassFromType[objectType] = klassPtr;
633 typeFromKlass[klassPtr] = objectType;
634 }
635
636 public static System.Collections.Concurrent.ConcurrentDictionary<System.Type, System.IntPtr> klassFromType
637 = new System.Collections.Concurrent.ConcurrentDictionary<System.Type, System.IntPtr>();
638
639 public static System.Collections.Concurrent.ConcurrentDictionary<System.IntPtr, System.Type> typeFromKlass
640 = new System.Collections.Concurrent.ConcurrentDictionary<System.IntPtr, System.Type>();
641
642 private static readonly object klassAllocLock = new object();
643}
644
532public interface IOwnershipTag 645public interface IOwnershipTag
533{ 646{
534} 647}
@@ -587,6 +700,46 @@ public class MarshalTest<T, U> : ICustomMarshaler
587 } 700 }
588} 701}
589 702
703///<summary>Marshals between System.Type instances and Eo classes (IntPtrs).</summary>
704public class MarshalEflClass : ICustomMarshaler
705{
706 public static ICustomMarshaler GetInstance(string cookie)
707 {
708 Eina.Log.Debug("MarshalTest.GetInstance cookie " + cookie);
709 return new MarshalEflClass();
710 }
711 public void CleanUpManagedData(object ManagedObj)
712 {
713 }
714
715 public void CleanUpNativeData(IntPtr pNativeData)
716 {
717 }
718
719 public int GetNativeDataSize()
720 {
721 Eina.Log.Debug("MarshalTest.GetNativeDataSize");
722 return 0;
723 }
724
725 public IntPtr MarshalManagedToNative(object ManagedObj)
726 {
727 Eina.Log.Debug("MarshalTest.MarshallManagedToNative");
728 if (ManagedObj == null)
729 return IntPtr.Zero;
730 var t = (System.Type) ManagedObj;
731 return Efl.Eo.ClassRegister.GetKlass(t);
732 }
733
734 public object MarshalNativeToManaged(IntPtr pNativeData)
735 {
736 Eina.Log.Debug("MarshalTest.MarshalNativeToManaged");
737 if (pNativeData == IntPtr.Zero)
738 return null;
739 return Efl.Eo.ClassRegister.GetManagedType(pNativeData);
740 }
741}
742
590public class StringPassOwnershipMarshaler : ICustomMarshaler { 743public class StringPassOwnershipMarshaler : ICustomMarshaler {
591 public object MarshalNativeToManaged(IntPtr pNativeData) { 744 public object MarshalNativeToManaged(IntPtr pNativeData) {
592 var ret = Eina.StringConversion.NativeUtf8ToManagedString(pNativeData); 745 var ret = Eina.StringConversion.NativeUtf8ToManagedString(pNativeData);
diff --git a/src/bindings/mono/meson.build b/src/bindings/mono/meson.build
index a8f5c79..ed6f91b 100644
--- a/src/bindings/mono/meson.build
+++ b/src/bindings/mono/meson.build
@@ -13,6 +13,7 @@ mono_sublibs = [
13] 13]
14 14
15blacklisted_files = [ 15blacklisted_files = [
16 'efl_class.eo',
16 'efl_canvas_text.eo', 17 'efl_canvas_text.eo',
17 'efl_canvas_scene3d.eo', 18 'efl_canvas_scene3d.eo',
18 'evas_canvas3d_camera.eo', 19 'evas_canvas3d_camera.eo',
diff --git a/src/tests/efl_mono/Eo.cs b/src/tests/efl_mono/Eo.cs
index 9da7752..c31c1ad 100644
--- a/src/tests/efl_mono/Eo.cs
+++ b/src/tests/efl_mono/Eo.cs
@@ -400,4 +400,17 @@ class TestInterfaceConcrete
400 } 400 }
401} 401}
402 402
403class TestProvider
404{
405 public static void test_find_provider()
406 {
407 // Tests only the direction C# -> C
408 var tmp = new Dummy.Numberwrapper();
409 var obj = new Dummy.TestObject();
410 Dummy.Numberwrapper provider = Dummy.Numberwrapper.static_cast(obj.FindProvider(typeof(Dummy.Numberwrapper)));
411 Test.AssertEquals(provider.GetType(), typeof(Dummy.Numberwrapper));
412 Test.AssertEquals(provider.GetNumber(), 1999);
413 }
414}
415
403} 416}
diff --git a/src/tests/efl_mono/dummy_test_object.eo b/src/tests/efl_mono/dummy_test_object.eo
index c6f2bb7..72750fb 100644
--- a/src/tests/efl_mono/dummy_test_object.eo
+++ b/src/tests/efl_mono/dummy_test_object.eo
@@ -1392,6 +1392,7 @@ class Dummy.Test_Object extends Efl.Object implements Efl.Part, Dummy.Test_Iface
1392 class.destructor; 1392 class.destructor;
1393 Efl.Object.constructor; 1393 Efl.Object.constructor;
1394 Efl.Part.part_get; 1394 Efl.Part.part_get;
1395 Efl.Object.provider_find;
1395 Dummy.Test_Iface.emit_test_conflicted; 1396 Dummy.Test_Iface.emit_test_conflicted;
1396 Dummy.Test_Iface.emit_nonconflicted; 1397 Dummy.Test_Iface.emit_nonconflicted;
1397 Dummy.Test_Iface.iface_prop { get; set; } 1398 Dummy.Test_Iface.iface_prop { get; set; }
diff --git a/src/tests/efl_mono/libefl_mono_native_test.c b/src/tests/efl_mono/libefl_mono_native_test.c
index d702127..1769c61 100644
--- a/src/tests/efl_mono/libefl_mono_native_test.c
+++ b/src/tests/efl_mono/libefl_mono_native_test.c
@@ -73,6 +73,7 @@ typedef struct Dummy_Test_Object_Data
73 Eina_List *list_for_accessor; 73 Eina_List *list_for_accessor;
74 int setter_only; 74 int setter_only;
75 int iface_prop; 75 int iface_prop;
76 Eo *provider;
76} Dummy_Test_Object_Data; 77} Dummy_Test_Object_Data;
77 78
78typedef struct Dummy_Numberwrapper_Data 79typedef struct Dummy_Numberwrapper_Data
@@ -150,6 +151,9 @@ _dummy_test_object_efl_object_constructor(Eo *obj, Dummy_Test_Object_Data *pd)
150 pd->part_two = efl_add(DUMMY_TEST_OBJECT_CLASS, obj, efl_name_set(efl_added, "part_two")); 151 pd->part_two = efl_add(DUMMY_TEST_OBJECT_CLASS, obj, efl_name_set(efl_added, "part_two"));
151 } 152 }
152 153
154 pd->provider = efl_add(DUMMY_NUMBERWRAPPER_CLASS, obj);
155 dummy_numberwrapper_number_set(pd->provider, 1999);
156
153 return obj; 157 return obj;
154} 158}
155 159
@@ -3920,6 +3924,14 @@ int _dummy_test_object_dummy_test_iface_iface_prop_get(EINA_UNUSED const Eo *obj
3920 return pd->iface_prop; 3924 return pd->iface_prop;
3921} 3925}
3922 3926
3927Eo * _dummy_test_object_efl_object_provider_find(EINA_UNUSED const Eo *obj, Dummy_Test_Object_Data *pd, const Efl_Class *klass)
3928{
3929 EINA_LOG_ERR("klass: %p, NUMBERWRAPPER: %p", klass, DUMMY_NUMBERWRAPPER_CLASS);
3930 if (klass == DUMMY_NUMBERWRAPPER_CLASS)
3931 return pd->provider;
3932 return efl_provider_find(efl_super(obj, DUMMY_TEST_OBJECT_CLASS), klass);
3933}
3934
3923/// Dummy.Child 3935/// Dummy.Child
3924 3936
3925static Efl_Object * 3937static Efl_Object *