diff --git a/src/Generation/Generator/Model/Property.cs b/src/Generation/Generator/Model/Property.cs index 45046f522..eceed5eba 100644 --- a/src/Generation/Generator/Model/Property.cs +++ b/src/Generation/Generator/Model/Property.cs @@ -141,8 +141,8 @@ public static void ThrowIfNotSupported(GirModel.ComplexType complexType, GirMode if (property.AnyType.Is()) return; - if (property.AnyType.Is()) - throw new System.NotImplementedException("There is currently no concept for transfering native records (structs) into the managed world."); + if (property.AnyType.Is(out var record) && (Record.IsTyped(record) || Record.IsForeignTyped(record) || Record.IsOpaqueTyped(record))) + return; throw new System.Exception($"Property {complexType.Name}.{property.Name} is not supported"); } diff --git a/src/Generation/Generator/Renderer/Public/ForeignTypedRecord.cs b/src/Generation/Generator/Renderer/Public/ForeignTypedRecord.cs index 77dcebdda..d94848157 100644 --- a/src/Generation/Generator/Renderer/Public/ForeignTypedRecord.cs +++ b/src/Generation/Generator/Renderer/Public/ForeignTypedRecord.cs @@ -24,7 +24,7 @@ namespace {Namespace.GetPublicName(record.Namespace)}; // AUTOGENERATED FILE - DO NOT MODIFY {PlatformSupportAttribute.Render(record as GirModel.PlatformDependent)} -public partial class {name} +public partial class {name} : GLib.BoxedRecord {{ public {internalHandleName} Handle {{ get; }} @@ -43,6 +43,11 @@ public partial class {name} // Implement this to perform additional steps in the constructor partial void Initialize(); + System.IntPtr GLib.BoxedRecord.GetHandle() + {{ + return Handle.DangerousGetHandle(); + }} + {FunctionRenderer.Render(record.TypeFunction)} }}"; } diff --git a/src/Generation/Generator/Renderer/Public/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Public/OpaqueTypedRecord.cs index 6c20b67ec..a46fd2f48 100644 --- a/src/Generation/Generator/Renderer/Public/OpaqueTypedRecord.cs +++ b/src/Generation/Generator/Renderer/Public/OpaqueTypedRecord.cs @@ -24,7 +24,7 @@ namespace {Namespace.GetPublicName(record.Namespace)}; // AUTOGENERATED FILE - DO NOT MODIFY {PlatformSupportAttribute.Render(record as GirModel.PlatformDependent)} -public partial class {name} +public partial class {name} : GLib.BoxedRecord {{ public {internalHandleName} Handle {{ get; }} @@ -57,6 +57,11 @@ public partial class {name} .Where(Method.IsEnabled) .Select(MethodRenderer.Render) .Join(Environment.NewLine)} + + System.IntPtr GLib.BoxedRecord.GetHandle() + {{ + return Handle.DangerousGetHandle(); + }} }}"; } } diff --git a/src/Generation/Generator/Renderer/Public/TypedRecord.cs b/src/Generation/Generator/Renderer/Public/TypedRecord.cs index 22da2d3da..68806f01f 100644 --- a/src/Generation/Generator/Renderer/Public/TypedRecord.cs +++ b/src/Generation/Generator/Renderer/Public/TypedRecord.cs @@ -25,7 +25,7 @@ namespace {Namespace.GetPublicName(record.Namespace)}; // AUTOGENERATED FILE - DO NOT MODIFY {PlatformSupportAttribute.Render(record as GirModel.PlatformDependent)} -public partial class {name} +public partial class {name} : GLib.BoxedRecord {{ public {internalHandleName} Handle {{ get; }} @@ -66,6 +66,11 @@ public partial class {name} .Where(Method.IsEnabled) .Select(MethodRenderer.Render) .Join(Environment.NewLine)} + + System.IntPtr GLib.BoxedRecord.GetHandle() + {{ + return Handle.DangerousGetHandle(); + }} }}"; } diff --git a/src/Libs/GLib-2.0/Public/BoxedRecord.cs b/src/Libs/GLib-2.0/Public/BoxedRecord.cs new file mode 100644 index 000000000..e634c1330 --- /dev/null +++ b/src/Libs/GLib-2.0/Public/BoxedRecord.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace GLib; + +/// +/// Defines that this type is a boxed record in GObject terms. +/// +/// Do not implement manually. All implementations of this interface are automatically generated. +public interface BoxedRecord +{ + System.IntPtr GetHandle(); +} diff --git a/src/Libs/GObject-2.0/Public/Value.cs b/src/Libs/GObject-2.0/Public/Value.cs index c11471dc8..6b2c6fb18 100644 --- a/src/Libs/GObject-2.0/Public/Value.cs +++ b/src/Libs/GObject-2.0/Public/Value.cs @@ -186,6 +186,9 @@ internal void Set(object? value) var strArray = Utf8StringArrayNullTerminatedOwnedHandle.Create(array); SetBoxed(strArray.DangerousGetHandle()); break; + case GLib.BoxedRecord b: + SetBoxed(b.GetHandle()); + break; case GLib.Variant v: SetVariant(v); break; diff --git a/src/Native/GirTestLib/girtest-property-tester.c b/src/Native/GirTestLib/girtest-property-tester.c index bffa8c49b..678cc734d 100644 --- a/src/Native/GirTestLib/girtest-property-tester.c +++ b/src/Native/GirTestLib/girtest-property-tester.c @@ -1,4 +1,5 @@ #include "girtest-property-tester.h" +#include "girtest-typed-record-tester.h" /** * GirTestPropertyTester: @@ -10,6 +11,7 @@ typedef enum { PROP_STRING_VALUE = 1, PROP_PROPERTY_TESTER = 2, + PROP_TYPED_RECORD_VALUE = 3, N_PROPERTIES } PropertyTesterProperty; @@ -19,6 +21,7 @@ struct _GirTestPropertyTester gchar *string_value; gchar *property_tester; + GirTestTypedRecordTester* record; }; G_DEFINE_TYPE(GirTestPropertyTester, girtest_property_tester, G_TYPE_OBJECT) @@ -42,6 +45,9 @@ girtest_property_tester_get_property (GObject *object, case PROP_PROPERTY_TESTER: g_value_set_string (value, self->property_tester); break; + case PROP_TYPED_RECORD_VALUE: + g_value_set_boxed (value, self->record); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -63,6 +69,9 @@ girtest_property_tester_set_property (GObject *object, case PROP_PROPERTY_TESTER: self->property_tester = g_value_dup_string (value); break; + case PROP_TYPED_RECORD_VALUE: + self->record = g_value_get_boxed (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -95,6 +104,13 @@ girtest_property_tester_class_init(GirTestPropertyTesterClass *class) NULL /* default value */, G_PARAM_READWRITE); + /** + * GirPropertyTester:record-value: + * Contains a typed record tester + */ + properties[PROP_TYPED_RECORD_VALUE] = + g_param_spec_boxed ("record-value", NULL, NULL, GIRTEST_TYPE_TYPED_RECORD_TESTER, G_PARAM_READWRITE); + g_object_class_install_properties (object_class, N_PROPERTIES, properties); } diff --git a/src/Tests/Libs/GirTest-0.1.Tests/PropertyTest.cs b/src/Tests/Libs/GirTest-0.1.Tests/PropertyTest.cs index 48cf76ca8..6624b01ea 100644 --- a/src/Tests/Libs/GirTest-0.1.Tests/PropertyTest.cs +++ b/src/Tests/Libs/GirTest-0.1.Tests/PropertyTest.cs @@ -26,6 +26,9 @@ public void TestNullStringProperty() obj.StringValue.Should().Be(text); obj.StringValue = null; obj.StringValue.Should().BeNull(); + + PropertyTester.StringValuePropertyDefinition.UnmanagedName.Should().Be("string-value"); + PropertyTester.StringValuePropertyDefinition.ManagedName.Should().Be(nameof(PropertyTester.StringValue)); } [TestMethod] @@ -34,5 +37,22 @@ public void PropertyNamedLikeClass() //Properties named like a class are suffixed with an underscore. var obj = PropertyTester.New(); obj.PropertyTester_ = "test"; + + PropertyTester.PropertyTester_PropertyDefinition.UnmanagedName.Should().Be("property-tester"); + PropertyTester.PropertyTester_PropertyDefinition.ManagedName.Should().Be(nameof(PropertyTester.PropertyTester_)); + } + + [TestMethod] + public void SupportsTypedRecordProperty() + { + var r = TypedRecordTester.New(); + r.CustomBitfield = TypedRecordTesterBitfield.One | TypedRecordTesterBitfield.Zero; + var obj = PropertyTester.New(); + obj.RecordValue = r; + + obj.RecordValue.CustomBitfield.Should().Be(TypedRecordTesterBitfield.One | TypedRecordTesterBitfield.Zero); + + PropertyTester.RecordValuePropertyDefinition.UnmanagedName.Should().Be("record-value"); + PropertyTester.RecordValuePropertyDefinition.ManagedName.Should().Be(nameof(PropertyTester.RecordValue)); } }