{
return
c_name == "efl_event_callback_array_priority_add"
+ || c_name == "efl_constructor"
|| c_name == "efl_player_position_get"
|| c_name == "efl_ui_widget_focus_set"
|| c_name == "efl_ui_widget_focus_get"
}
bool operator()(grammar::attributes::klass_name const& cls) const
{
- return as_generator("new " + name_helpers::klass_full_concrete_name(cls) + "(evt.Info)").generate(sink, attributes::unused, *context);
+ return as_generator("(Efl.Eo.Globals.CreateWrapperFor(evt.Info) as " + name_helpers::klass_full_concrete_name(cls) + ")").generate(sink, attributes::unused, *context);
}
bool operator()(attributes::complex_type_def const&) const
{
/****/
<< scope_tab << scope_tab << "Eina.Log.Debug(\"function " << string << " was called\");\n"
/****/
- << scope_tab << scope_tab << "Efl.Eo.IWrapper wrapper = Efl.Eo.Globals.data_get(pd);\n"
+ << scope_tab << scope_tab << "Efl.Eo.IWrapper wrapper = Efl.Eo.Globals.PrivateDataGet(pd);\n"
<< scope_tab << scope_tab << "if(wrapper != null) {\n"
<< scope_tab << scope_tab << scope_tab << eolian_mono::native_function_definition_preamble()
<< scope_tab << scope_tab << scope_tab << "try {\n"
namespace eolian_mono {
template <typename OutputIterator, typename Context>
-static bool generate_static_cast_method(OutputIterator sink, grammar::attributes::klass_def const& cls, Context const &context)
-{
- return as_generator(
- scope_tab << "///<summary>Casts obj into an instance of this type.</summary>\n"
- << scope_tab << "public " << (helpers::has_regular_ancestor(cls) ? "new " : "") <<"static " << name_helpers::klass_concrete_name(cls) << " static_cast(Efl.Object obj)\n"
- << scope_tab << "{\n"
- << scope_tab << scope_tab << "if (obj == null)\n"
- << scope_tab << scope_tab << scope_tab << "throw new System.ArgumentNullException(\"obj\");\n"
- << scope_tab << scope_tab << "return new " << name_helpers::klass_concrete_name(cls) << "(obj.NativeHandle);\n"
- << scope_tab << "}\n"
- ).generate(sink, nullptr, context);
-}
-
-template <typename OutputIterator, typename Context>
static bool generate_equals_method(OutputIterator sink, Context const &context)
{
return as_generator(
suffix = "CLASS";
break;
case attributes::class_type::abstract_:
- class_type = "class";
+ class_type = "abstract class";
suffix = "CLASS";
break;
case attributes::class_type::mixin:
});
// Concrete class for interfaces, mixins, etc.
- if(class_type != "class")
+ if(class_type != "class" && class_type != "abstract class")
{
auto concrete_cxt = context_add_tag(class_context{class_context::concrete}, context);
auto concrete_name = name_helpers::klass_concrete_name(cls);
<< ")] internal static extern System.IntPtr\n"
<< scope_tab << scope_tab << name_helpers::klass_get_name(cls) << "();\n"
<< scope_tab << "///<summary>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 << "public " << concrete_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
+ << scope_tab << "private " << concrete_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << (root ? "handle = raw;\n" : "")
<< scope_tab << scope_tab << "RegisterEventProxies();\n"
if (!generate_dispose_methods(sink, cls, concrete_cxt))
return false;
- if (!generate_static_cast_method(sink, cls, concrete_cxt))
- return false;
-
if (!generate_equals_method(sink, concrete_cxt))
return false;
}
// Inheritable class
- if(class_type == "class")
+ if(class_type == "class" || class_type == "abstract class")
{
auto inherit_cxt = context_add_tag(class_context{class_context::inherit}, context);
if (!generate_dispose_methods(sink, cls, inherit_cxt))
return false;
- if (!generate_static_cast_method(sink, cls, inherit_cxt))
- return false;
-
if (!generate_equals_method(sink, inherit_cxt))
return false;
<< scope_tab << "}\n"
).generate(sink, attributes::unused, inative_cxt))
return false;
-
+
// Native method definitions
if(!as_generator(*(native_function_definition(cls)))
.generate(sink, helpers::get_all_implementable_methods(cls), inative_cxt)) return false;
<< scope_tab << scope_tab << "FinishInstantiation();\n"
<< scope_tab << "}\n"
<< scope_tab << "///<summary>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 << "public " << inherit_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
+ << scope_tab << "protected " << inherit_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << (root ? "handle = raw;\n" : "")
<< scope_tab << scope_tab << "RegisterEventProxies();\n"
).generate(sink, std::make_tuple(constructors, constructors, constructors), context))
return false;
+ // Some abstract classes (like Efl.App) have a simple regular class that is used to instantiate them
+ // in a controlled manner. These fake-private classes can be returned from C and we use a similarly-named
+ // private class to be able to instantiate them when they get to the C# world.
+ if (cls.type == attributes::class_type::abstract_)
+ {
+ if (!as_generator(
+ scope_tab << "[Efl.Eo.PrivateNativeClass]\n"
+ << scope_tab << "private class " << inherit_name << "Realized : " << inherit_name << "\n"
+ << scope_tab << "{\n"
+ << scope_tab << scope_tab << "private " << inherit_name << "Realized(IntPtr ptr) : base(ptr)\n"
+ << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << "}\n"
+ << scope_tab << "}\n"
+ ).generate(sink, attributes::unused, context))
+ return false;
+ }
+
// Internal constructors
if (!root)
{
<< scope_tab << scope_tab << "}\n"
<< scope_tab << scope_tab << "handle = Efl.Eo.Globals.instantiate_start(actual_klass, parent);\n"
<< scope_tab << scope_tab << "RegisterEventProxies();\n"
+ << scope_tab << scope_tab << "if (inherited)\n"
+ << scope_tab << scope_tab << "{\n"
+ << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.PrivateDataSet(this);\n"
+ << scope_tab << scope_tab << "}\n"
<< scope_tab << "}\n"
<< scope_tab << "protected void FinishInstantiation()\n"
<< scope_tab << "{\n"
- << scope_tab << scope_tab << "if (inherited) {\n"
- << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.data_set(this);\n"
- << scope_tab << 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"
<< scope_tab << "{\n"
<< scope_tab << scope_tab << "get\n"
<< scope_tab << scope_tab << "{\n"
- << scope_tab << scope_tab << scope_tab << "Efl.Object obj = Efl.IPartNativeInherit.efl_part_get_ptr.Value.Delegate(NativeHandle, \"" << part.name << "\");\n"
- << scope_tab << scope_tab << scope_tab << "return " << part_klass_name << ".static_cast(obj);\n"
+ << scope_tab << scope_tab << scope_tab << "return Efl.IPartNativeInherit.efl_part_get_ptr.Value.Delegate(NativeHandle, \"" << part.name << "\") as " << part_klass_name << ";\n"
<< scope_tab << scope_tab << "}\n"
<< scope_tab << "}\n"
).generate(sink, part.documentation, context);
if (!as_generator(
"\n"
<< indent << scope_tab << scope_tab << "_external_struct." << string
- << " = (" << concrete_name << ") System.Activator.CreateInstance(typeof("
- << concrete_name << "), new System.Object[] {_internal_struct." << string << "});\n"
- << indent << scope_tab << scope_tab << "Efl.Eo.Globals.efl_ref(_internal_struct." << string << ");\n")
- .generate(sink, std::make_tuple(field_name, field_name, field_name), context))
+ << " = (" << concrete_name << ") Efl.Eo.Globals.CreateWrapperFor(_internal_struct." << string << ");\n"
+ ).generate(sink, std::make_tuple(field_name, field_name), context))
return false;
}
else if (field.type.c_type == "Eina_Binbuf *" || field.type.c_type == "const Eina_Binbuf *")
using System.Linq;
using System.Runtime.InteropServices;
using System.Collections.Generic;
+using System.Reflection;
using Eina.Callbacks;
using static Eina.HashNativeFunctions;
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;
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)
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))
{
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Reflection;
using System.Threading;
using static Eina.NativeCustomExportFunctions;
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)
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)
{
{
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);
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);
}
}
- 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)
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
[System.AttributeUsage(System.AttributeTargets.Class |
System.AttributeTargets.Interface,
AllowMultiple = false,
- Inherited = true)
+ Inherited = false)
]
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>
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)
{
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))
{
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));
}
}
Test.AssertEquals(parent, child.GetParent());
- var parent_retrieved = Dummy.TestObject.static_cast(child.GetParent());
+ var parent_retrieved = child.GetParent() as Dummy.TestObject;
Test.AssertEquals(parent, parent_retrieved);
}
Test.AssertEquals(parent, child.GetParent());
- Dummy.Numberwrapper parent_retrieved = Dummy.Numberwrapper.static_cast(child.GetParent());
+ Dummy.Numberwrapper parent_retrieved = child.GetParent() as Dummy.Numberwrapper;
Test.AssertEquals(parent, parent_retrieved);
}
Test.AssertEquals(parent, child.GetParent());
- var parent_from_cast = Dummy.TestObject.static_cast(child.GetParent());
+ var parent_from_cast = child.GetParent() as Derived;
Test.AssertEquals(parent, parent_from_cast);
}
}
public static void test_iface_concrete_methods()
{
var obj = new Dummy.TestObject();
- Dummy.ITestIface iface = Dummy.ITestIfaceConcrete.static_cast(obj);
+ Dummy.ITestIface iface = obj.ReturnIface();
iface.IfaceProp = 1970;
Test.AssertEquals(iface.IfaceProp, 1970);
{
// Tests only the direction C# -> C
var obj = new Dummy.TestObject();
- Dummy.Numberwrapper provider = Dummy.Numberwrapper.static_cast(obj.FindProvider(typeof(Dummy.Numberwrapper)));
+ Dummy.Numberwrapper provider = obj.FindProvider(typeof(Dummy.Numberwrapper)) as Dummy.Numberwrapper;
Test.AssertEquals(provider.GetType(), typeof(Dummy.Numberwrapper));
Test.AssertEquals(provider.GetNumber(), 1999);
}
return: Dummy.Test_Object;
}
+ return_iface {
+ return: Dummy.Test_Iface;
+ }
+
int_out {
params {
@in x: int;
# endif
#endif
+#include "dummy_test_iface.eo.h"
+#include "dummy_inherit_iface.eo.h"
#include "dummy_numberwrapper.eo.h"
#include "dummy_test_object.eo.h"
#include "dummy_child.eo.h"
-#include "dummy_test_iface.eo.h"
-#include "dummy_inherit_iface.eo.h"
#include "dummy_inherit_helper.eo.h"
#include "dummy_part_holder.eo.h"
return NULL;
}
+Dummy_Test_Iface *_dummy_test_object_return_iface(Eo *obj, EINA_UNUSED Dummy_Test_Object_Data *pd)
+{
+ return obj;
+}
+
void _dummy_test_object_int_out(EINA_UNUSED Eo *obj, EINA_UNUSED Dummy_Test_Object_Data *pd, int x, int *y)
{
*y = -x;