aboutsummaryrefslogtreecommitdiffstats
path: root/src/bindings
diff options
context:
space:
mode:
authorLauro Moura <lauromoura@expertisesolutions.com.br>2019-04-05 19:53:37 -0300
committerVitor Sousa <vitorsousa@expertisesolutions.com.br>2019-04-05 19:56:42 -0300
commit1e22db1150049e313bcba7906fc5ffc9a745eaf0 (patch)
tree3dd72d0486e2e03d90e10e5f96554176326aa783 /src/bindings
parentmeson: correctly use the correct dependency (diff)
downloadefl-1e22db1150049e313bcba7906fc5ffc9a745eaf0.tar.gz
csharp: Make classes abstract and rework casting
Summary: Abstract Eo classes are now proper C# abstract classes. As a side effect, returning Eo instances from native code was reworked to return instances of their actual Eo classes instead of previous behavior of returning a generic Efl.Object and using static_cast. Instead of `var window = Efl.Ui.Win.static_cast(widget.GetParent());` Use `var window = widget.GetParent() as Efl.Ui.Win;` Another side effect was that `efl_constructor` was removed from the list of supported `Efl.Object` overrides. It is invoked inside `efl_add_internal_start`, before the bindings makes the association of the newly created EoId with the C# instance that created it, making the managed delegate meaningless. C# users then can use regular C# constructors to initialize fields. Also changed to set the private data of C#-inherited classes before the call to constructing methods (aka constructor parameters) so C# classes can override them correctly. Fixes https://phab.enlightenment.org/T7778 Fixes https://phab.enlightenment.org/T7757 Reviewers: vitor.sousa, felipealmeida, segfaultxavi Reviewed By: vitor.sousa, segfaultxavi Subscribers: cedric, #reviewers, #committers Tags: #efl Maniphest Tasks: https://phab.enlightenment.org/T7778, https://phab.enlightenment.org/T7757, https://phab.enlightenment.org/T7702 Differential Revision: https://phab.enlightenment.org/D8550
Diffstat (limited to 'src/bindings')
-rw-r--r--src/bindings/mono/eina_mono/eina_container_common.cs14
-rw-r--r--src/bindings/mono/eo_mono/iwrapper.cs128
2 files changed, 119 insertions, 23 deletions
diff --git a/src/bindings/mono/eina_mono/eina_container_common.cs b/src/bindings/mono/eina_mono/eina_container_common.cs
index 73a3a0f46a..9695c098da 100644
--- a/src/bindings/mono/eina_mono/eina_container_common.cs
+++ b/src/bindings/mono/eina_mono/eina_container_common.cs
@@ -4,6 +4,7 @@ using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Collections.Generic;
+using System.Reflection;
using Eina.Callbacks;
using static Eina.HashNativeFunctions;
@@ -196,13 +197,6 @@ public class StringElementTraits : IBaseElementTraits<string>
public class EflObjectElementTraits<T> : IBaseElementTraits<T>
{
- private System.Type concreteType = null;
-
- public EflObjectElementTraits(System.Type concrete)
- {
- concreteType = concrete;
- }
-
public IntPtr ManagedToNativeAlloc(T man)
{
IntPtr h = ((Efl.Eo.IWrapper)man).NativeHandle;
@@ -290,7 +284,7 @@ public class EflObjectElementTraits<T> : IBaseElementTraits<T>
return default(T);
}
- return (T)Activator.CreateInstance(concreteType, Efl.Eo.Globals.efl_ref(nat));
+ return (T) Efl.Eo.Globals.CreateWrapperFor(nat, shouldIncRef: true);
}
public T NativeToManagedRef(IntPtr nat)
@@ -762,7 +756,9 @@ public static class TraitFunctions
throw new Exception("Failed to get a suitable concrete class for this type.");
}
- traits = new EflObjectElementTraits<T>(concrete);
+ // No need to pass concrete as the traits class will use reflection to get the actually most
+ // derived type returned.
+ traits = new EflObjectElementTraits<T>();
}
else if (IsString(type))
{
diff --git a/src/bindings/mono/eo_mono/iwrapper.cs b/src/bindings/mono/eo_mono/iwrapper.cs
index 43835aabd7..3600cdec50 100644
--- a/src/bindings/mono/eo_mono/iwrapper.cs
+++ b/src/bindings/mono/eo_mono/iwrapper.cs
@@ -4,6 +4,7 @@ using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Reflection;
using System.Threading;
using static Eina.NativeCustomExportFunctions;
@@ -289,7 +290,7 @@ public class Globals
return ifaces_lst;
}
- private static Efl.Eo.NativeClass get_native_class(System.Type type)
+ private static Efl.Eo.NativeClass GetNativeClass(System.Type type)
{
var attrs = System.Attribute.GetCustomAttributes(type);
foreach (var attr in attrs)
@@ -306,7 +307,7 @@ public class Globals
public static byte class_initializer_call(IntPtr klass, System.Type type)
{
Eina.Log.Debug($"called with 0x{klass.ToInt64():x} {type}");
- Efl.Eo.NativeClass nativeClass = get_native_class(type.BaseType);
+ Efl.Eo.NativeClass nativeClass = GetNativeClass(type.BaseType);
if (nativeClass != null)
{
@@ -320,7 +321,7 @@ public class Globals
{
if (!System.Array.Exists(base_interfaces, element => element == iface))
{
- var nc = get_native_class(iface);
+ var nc = GetNativeClass(iface);
if (nc != null)
{
var moredescs = nc.GetEoOps(type);
@@ -442,7 +443,7 @@ public class Globals
return eo;
}
- public static void data_set(Efl.Eo.IWrapper obj)
+ 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);
@@ -454,7 +455,7 @@ public class Globals
}
}
- public static Efl.Eo.IWrapper data_get(IntPtr pd)
+ public static Efl.Eo.IWrapper PrivateDataGet(IntPtr pd)
{
EolianPD epd = (EolianPD)Marshal.PtrToStructure(pd, typeof(EolianPD));
if (epd.pointer != IntPtr.Zero)
@@ -542,6 +543,80 @@ public class Globals
return tcs.Task;
}
+
+ /// <summary>Returns whether the given type was generated by eolian-mono</summary>
+ /// <param name="managedType">The type to check.</param>
+ /// <returns>True if generated by eolian-mono. False otherwise.</returns>
+ private static bool IsGeneratedClass(System.Type managedType)
+ {
+ return GetNativeClass(managedType) != null;
+ }
+
+ /// <summary>Creates a new wrapper for the given Eo id.
+ ///
+ /// <para>If the Eo was created from a non-generated class (i.e. C#-pure class), it returns
+ /// the C# instance handle stored in the Eo's private data.</para>
+ ///
+ /// <para>For generated-class Eo instance, we use reflection to get the correct C# type to re-wrap
+ /// it.</para>
+ /// </summary>
+ ///
+ /// <param name="handle">The Eo id to be wrapped.</param>
+ /// <param name="shouldIncRef">Whether we should increase the refcount of the Eo instance.</param>
+ /// <returns>The C# wrapper for this instance.</returns>
+ public static Efl.Eo.IWrapper CreateWrapperFor(System.IntPtr handle, bool shouldIncRef=true)
+ {
+ IntPtr eoKlass = efl_class_get(handle);
+
+ if (eoKlass == IntPtr.Zero)
+ {
+ 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)
+ {
+ instance = PrivateDataGet(pd);
+ }
+
+ return instance;
+ }
+
+ 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;
+ }
} // Globals
public static class Config
@@ -560,7 +635,7 @@ public static class Config
[System.AttributeUsage(System.AttributeTargets.Class |
System.AttributeTargets.Interface,
AllowMultiple = false,
- Inherited = true)
+ Inherited = false)
]
public abstract class NativeClass : System.Attribute
{
@@ -568,6 +643,22 @@ public abstract class NativeClass : System.Attribute
public abstract System.Collections.Generic.List<Efl_Op_Description> GetEoOps(System.Type type);
}
+/// <summary>Attribute for private native classes.
+///
+/// <para>For internal usage by generated code only.</para></summary>
+public class PrivateNativeClass : NativeClass
+{
+ public override IntPtr GetEflClass()
+ {
+ return IntPtr.Zero;
+ }
+
+ public override System.Collections.Generic.List<Efl_Op_Description> GetEoOps(System.Type type)
+ {
+ return null;
+ }
+}
+
public interface IWrapper
{
/// <summary>Pointer to internal Eo instance.</summary>
@@ -605,6 +696,16 @@ public static class ClassRegister
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))
+ {
+ name = name.Substring(0, name.Length - abstract_impl_suffix.Length);
+ var lastDot = name.LastIndexOf(".");
+ var klassName = name.Substring(lastDot + 1);
+ name += "+" + klassName + abstract_impl_suffix; // '+' is the separator for nested classes
+ }
+
// When converting to managed, interfaces and mixins gets the 'I' prefix.
if (klass_type == Efl.Eo.Globals.EflClassType.Interface || klass_type == Efl.Eo.Globals.EflClassType.Mixin)
{
@@ -795,6 +896,12 @@ public class MarshalTest<T, U> : ICustomMarshaler
public IntPtr MarshalManagedToNative(object ManagedObj)
{
Eina.Log.Debug("MarshalTest.MarshallManagedToNative");
+
+ if (ManagedObj == null)
+ {
+ return IntPtr.Zero;
+ }
+
var r = ((IWrapper)ManagedObj).NativeHandle;
if (typeof(U) == typeof(OwnTag))
{
@@ -806,14 +913,7 @@ public class MarshalTest<T, U> : ICustomMarshaler
public object MarshalNativeToManaged(IntPtr pNativeData)
{
- Eina.Log.Debug("MarshalTest.MarshalNativeToManaged");
- if (typeof(U) != typeof(OwnTag))
- {
- Efl.Eo.Globals.efl_ref(pNativeData);
- }
-
- return Activator.CreateInstance(typeof(T), new System.Object[] {pNativeData});
- //return null;
+ return Efl.Eo.Globals.CreateWrapperFor(pNativeData, shouldIncRef : typeof(U) != typeof(OwnTag));
}
}