diff --git a/src/Generation/Generator3/Converter/Model/ParameterConverter.ToManaged.cs b/src/Generation/Generator3/Converter/Model/ParameterConverter.ToManaged.cs index 0751c9d4c..49942891d 100644 --- a/src/Generation/Generator3/Converter/Model/ParameterConverter.ToManaged.cs +++ b/src/Generation/Generator3/Converter/Model/ParameterConverter.ToManaged.cs @@ -110,7 +110,12 @@ public static partial class ParameterConverter var ownedHandle = from.Transfer == Transfer.Full; variableName = from.GetConvertedName(); - return $"var {variableName} = new {record.GetFullyQualifiedPublicClassName()}(new {record.GetFullyQualifiedInternalHandle()}({from.GetPublicName()}, {ownedHandle.ToString().ToLower()}));"; + + var handleClass = ownedHandle + ? record.GetFullyQualifiedInternalOwnedHandle() + : record.GetFullyQualifiedInternalUnownedHandle(); + + return $"var {variableName} = new {record.GetFullyQualifiedPublicClassName()}(new {handleClass}({from.GetPublicName()}));"; } #endregion diff --git a/src/Generation/Generator3/Converter/Model/ParameterConverter.ToNative.cs b/src/Generation/Generator3/Converter/Model/ParameterConverter.ToNative.cs index d130946f9..eb868f587 100644 --- a/src/Generation/Generator3/Converter/Model/ParameterConverter.ToNative.cs +++ b/src/Generation/Generator3/Converter/Model/ParameterConverter.ToNative.cs @@ -150,7 +150,7 @@ public static partial class ParameterConverter if (from.Nullable) { var record = (GirModel.Record) from.AnyType.AsT0; - variableName = from.GetPublicName() + "?.Handle ?? " + record.GetFullyQualifiedInternalNullHandle(); + variableName = from.GetPublicName() + "?.Handle ?? " + record.GetFullyQualifiedInternalNullHandleInstance(); } else { diff --git a/src/Generation/Generator3/Converter/Name/RecordNameConverter.cs b/src/Generation/Generator3/Converter/Name/RecordNameConverter.cs index d53622409..06b2b861a 100644 --- a/src/Generation/Generator3/Converter/Name/RecordNameConverter.cs +++ b/src/Generation/Generator3/Converter/Name/RecordNameConverter.cs @@ -8,8 +8,14 @@ public static string GetFullyQualifiedInternalStructName(this GirModel.Record re public static string GetFullyQualifiedInternalHandle(this GirModel.Record record) => record.Namespace.GetInternalName() + "." + GetInternalHandleName(record); - public static string GetFullyQualifiedInternalNullHandle(this GirModel.Record record) - => GetFullyQualifiedInternalHandle(record) + ".Null"; + public static string GetFullyQualifiedInternalNullHandleInstance(this GirModel.Record record) + => record.Namespace.GetInternalName() + "." + GetInternalNullHandleName(record) + "." + "Instance"; + + public static string GetFullyQualifiedInternalOwnedHandle(this GirModel.Record record) + => record.Namespace.GetInternalName() + "." + GetInternalOwnedHandleName(record); + + public static string GetFullyQualifiedInternalUnownedHandle(this GirModel.Record record) + => record.Namespace.GetInternalName() + "." + GetInternalUnownedHandleName(record); public static string GetFullyQualifiedInternalManagedHandleCreateMethod(this GirModel.Record record) => record.Namespace.GetInternalName() + "." + GetInternalManagedHandleName(record) + ".Create"; @@ -26,6 +32,15 @@ public static string GetInternalStructName(this GirModel.Record record) public static string GetInternalHandleName(this GirModel.Record record) => record.Name + "Handle"; + public static string GetInternalNullHandleName(this GirModel.Record record) + => record.Name + "NullHandle"; + + public static string GetInternalOwnedHandleName(this GirModel.Record record) + => record.Name + "OwnedHandle"; + + public static string GetInternalUnownedHandleName(this GirModel.Record record) + => record.Name + "UnownedHandle"; + public static string GetInternalManagedHandleName(this GirModel.Record record) => record.Name + "ManagedHandle"; } diff --git a/src/Generation/Generator3/Generation/Callback/InternalDelegate/InternalDelegateModel.cs b/src/Generation/Generator3/Generation/Callback/InternalDelegate/InternalDelegateModel.cs index 350ed899e..96cbdd877 100644 --- a/src/Generation/Generator3/Generation/Callback/InternalDelegate/InternalDelegateModel.cs +++ b/src/Generation/Generator3/Generation/Callback/InternalDelegate/InternalDelegateModel.cs @@ -13,7 +13,7 @@ public class InternalDelegateModel public string Name => _callback.Name; public string NamespaceName => _callback.Namespace.GetInternalName(); - public ReturnType ReturnType => _returnType ??= _callback.ReturnType.CreateInternalModel(); + public ReturnType ReturnType => _returnType ??= _callback.ReturnType.CreateInternalModelForCallback(); public IEnumerable Parameters => _parameters ??= _callback.Parameters.CreateInternalModelsForCallback(); public InternalDelegateModel(GirModel.Callback callback) diff --git a/src/Generation/Generator3/Generation/Record/InternalHandle/FreeMemoryCallRenderer.cs b/src/Generation/Generator3/Generation/Record/InternalHandle/FreeMemoryCallRenderer.cs index d71b3e992..b1afa1a14 100644 --- a/src/Generation/Generator3/Generation/Record/InternalHandle/FreeMemoryCallRenderer.cs +++ b/src/Generation/Generator3/Generation/Record/InternalHandle/FreeMemoryCallRenderer.cs @@ -5,7 +5,7 @@ public static class FreeMemoryCallRenderer public static string RenderFreeCall(this InternalHandleModel model) { return model.FreeMethod is null - ? $"throw new System.Exception(\"Can't free native handle of type \\\"{model.InternalNamespaceName}.{model.Name}\\\".\");" + ? $"throw new System.Exception(\"Can't free native handle of type \\\"{model.InternalNamespaceName}.{model.OwnedHandleName}\\\".\");" : @$"{model.FreeMethod.Name}(handle); return true;"; } diff --git a/src/Generation/Generator3/Generation/Record/InternalHandle/InternalHandleGenerator.cs b/src/Generation/Generator3/Generation/Record/InternalHandle/InternalHandleGenerator.cs index 4f8d900fa..5b7bc4749 100644 --- a/src/Generation/Generator3/Generation/Record/InternalHandle/InternalHandleGenerator.cs +++ b/src/Generation/Generator3/Generation/Record/InternalHandle/InternalHandleGenerator.cs @@ -19,7 +19,7 @@ public void Generate(GirModel.Record record) { var model = new InternalHandleModel(record); var source = _template.Render(model); - var codeUnit = new CodeUnit(record.Namespace.GetCanonicalName(), model.Name, source); + var codeUnit = new CodeUnit(record.Namespace.GetCanonicalName(), model.HandleName, source); _publisher.Publish(codeUnit); } catch diff --git a/src/Generation/Generator3/Generation/Record/InternalHandle/InternalHandleModel.cs b/src/Generation/Generator3/Generation/Record/InternalHandle/InternalHandleModel.cs index 4d431f666..3279c9b5d 100644 --- a/src/Generation/Generator3/Generation/Record/InternalHandle/InternalHandleModel.cs +++ b/src/Generation/Generator3/Generation/Record/InternalHandle/InternalHandleModel.cs @@ -6,7 +6,10 @@ namespace Generator3.Generation.Record { public class InternalHandleModel { - public string Name => Record.GetInternalHandleName(); + public string HandleName => Record.GetInternalHandleName(); + public string NullHandleName => Record.GetInternalNullHandleName(); + public string OwnedHandleName => Record.GetInternalOwnedHandleName(); + public string UnownedHandleName => Record.GetInternalUnownedHandleName(); public string InternalNamespaceName => Record.Namespace.GetInternalName(); public string NamespaceName => Record.Namespace.Name; public GirModel.Record Record { get; } diff --git a/src/Generation/Generator3/Generation/Record/InternalHandle/InternalHandleTemplate.cs b/src/Generation/Generator3/Generation/Record/InternalHandle/InternalHandleTemplate.cs index d2d46e689..26e0a089c 100644 --- a/src/Generation/Generator3/Generation/Record/InternalHandle/InternalHandleTemplate.cs +++ b/src/Generation/Generator3/Generation/Record/InternalHandle/InternalHandleTemplate.cs @@ -14,17 +14,33 @@ namespace { model.InternalNamespaceName } {{ // AUTOGENERATED FILE - DO NOT MODIFY - public partial class { model.Name } : SafeHandle + public abstract class {model.HandleName} : SafeHandle {{ - public static {model.Name} Null = new {model.Name}(); + protected {model.HandleName}(bool ownsHandle) : base(IntPtr.Zero, ownsHandle) {{ }} - protected {model.Name}() : base(IntPtr.Zero, true) {{}} - public {model.Name}(IntPtr handle, bool ownsHandle) : base(IntPtr.Zero, ownsHandle) + public sealed override bool IsInvalid => handle == IntPtr.Zero; + }} + + public class {model.NullHandleName} : {model.HandleName} + {{ + public static {model.NullHandleName} Instance = new {model.NullHandleName}(); + + private {model.NullHandleName}() : base(true) {{ }} + + protected override bool ReleaseHandle() {{ - SetHandle(handle); + throw new System.Exception(""It is not allowed to free a \""{model.InternalNamespaceName}.{model.NullHandleName}\"".""); }} + }} - public sealed override bool IsInvalid => handle == IntPtr.Zero; + public partial class {model.OwnedHandleName} : {model.HandleName} + {{ + private {model.OwnedHandleName}() : base(true) {{ }} + + public {model.OwnedHandleName}(IntPtr handle) : base(true) + {{ + SetHandle(handle); + }} protected override bool ReleaseHandle() {{ @@ -33,6 +49,21 @@ protected override bool ReleaseHandle() {model.RenderFreeFunction()} }} + + public partial class {model.UnownedHandleName} : {model.HandleName} + {{ + private {model.UnownedHandleName}() : base(false) {{ }} + + public {model.UnownedHandleName}(IntPtr handle) : base(false) + {{ + SetHandle(handle); + }} + + protected override bool ReleaseHandle() + {{ + throw new System.Exception(""It is not allowed to free a \""{model.InternalNamespaceName}.{model.UnownedHandleName}\"".""); + }} + }} }}"; } } diff --git a/src/Generation/Generator3/Generation/Record/InternalManagedHandle/InternalManagedHandleTemplate.cs b/src/Generation/Generator3/Generation/Record/InternalManagedHandle/InternalManagedHandleTemplate.cs index b74d5feff..62cc5a5ad 100644 --- a/src/Generation/Generator3/Generation/Record/InternalManagedHandle/InternalManagedHandleTemplate.cs +++ b/src/Generation/Generator3/Generation/Record/InternalManagedHandle/InternalManagedHandleTemplate.cs @@ -14,7 +14,7 @@ namespace { model.NamespaceName } {{ // AUTOGENERATED FILE - DO NOT MODIFY - public partial class { model.Name } : {model.BaseHandle} + public class { model.Name } : {model.BaseHandle} {{ public static {model.BaseHandle} Create({model.InternalStruct}? data = null) {{ @@ -34,7 +34,10 @@ public partial class { model.Name } : {model.BaseHandle} return new {model.Name}(ptr); }} - private {model.Name}(IntPtr handle) : base(handle, true) {{ }} + private {model.Name}(IntPtr handle) : base(true) + {{ + SetHandle(handle); + }} protected override bool ReleaseHandle() {{ diff --git a/src/Generation/Generator3/Generation/Record/PublicClass/PublicClassTemplate.cs b/src/Generation/Generator3/Generation/Record/PublicClass/PublicClassTemplate.cs index 00f14d26e..f39606ab1 100644 --- a/src/Generation/Generator3/Generation/Record/PublicClass/PublicClassTemplate.cs +++ b/src/Generation/Generator3/Generation/Record/PublicClass/PublicClassTemplate.cs @@ -24,15 +24,13 @@ public partial class {model.Name} : GLib.IHandle // Override this to perform additional steps in the constructor partial void Initialize(); - - public {model.Name}(IntPtr ptr, bool ownsHandle) : this(new Internal.{model.InternalHandleName}(ptr, ownsHandle)){{ }} public {model.Name}(Internal.{model.InternalHandleName} handle) {{ _handle = handle; Initialize(); }} - + // TODO: Default Constructor (allocate in managed memory and free on Dispose?) // We need to be able to create instances of records with full access to // fields, e.g. Gdk.Rectangle, Gtk.TreeIter, etc. diff --git a/src/Generation/Generator3/Model/Internal/Parameter/RecordParameter.cs b/src/Generation/Generator3/Model/Internal/Parameter/RecordParameter.cs index ac61fa0cd..facecdbb3 100644 --- a/src/Generation/Generator3/Model/Internal/Parameter/RecordParameter.cs +++ b/src/Generation/Generator3/Model/Internal/Parameter/RecordParameter.cs @@ -1,4 +1,6 @@ -using Generator3.Converter; +using System; +using Generator3.Converter; +using GirModel; namespace Generator3.Model.Internal { @@ -7,7 +9,18 @@ public class RecordParameter : Parameter private GirModel.Record Type => (GirModel.Record) Model.AnyType.AsT0; //Native records are represented as SafeHandles and are not nullable - public override string NullableTypeName => Type.GetFullyQualifiedInternalHandle(); + public override string NullableTypeName => Model switch + { + { Direction: global::GirModel.Direction.In } => Type.GetFullyQualifiedInternalHandle(), + { CallerAllocates: true } => Type.GetFullyQualifiedInternalHandle(), + { CallerAllocates: false, Direction: global::GirModel.Direction.InOut, Transfer: Transfer.Full } => Type.GetFullyQualifiedInternalOwnedHandle(), + { CallerAllocates: false, Direction: global::GirModel.Direction.InOut, Transfer: Transfer.Container } => Type.GetFullyQualifiedInternalOwnedHandle(), + { CallerAllocates: false, Direction: global::GirModel.Direction.InOut, Transfer: Transfer.None } => Type.GetFullyQualifiedInternalUnownedHandle(), + { CallerAllocates: false, Direction: global::GirModel.Direction.Out, Transfer: Transfer.Full } => Type.GetFullyQualifiedInternalOwnedHandle(), + { CallerAllocates: false, Direction: global::GirModel.Direction.Out, Transfer: Transfer.Container } => Type.GetFullyQualifiedInternalOwnedHandle(), + { CallerAllocates: false, Direction: global::GirModel.Direction.Out, Transfer: Transfer.None } => Type.GetFullyQualifiedInternalUnownedHandle(), + _ => throw new Exception($"Can't detect parameter type: CallerAllocates={Model.CallerAllocates} Direction={Model.Direction} Transfer={Model.Transfer}") + }; public override string Direction => Model.GetDirection( @in: ParameterDirection.In, diff --git a/src/Generation/Generator3/Model/Internal/ReturnType/CallbackReturnTypeFactory.cs b/src/Generation/Generator3/Model/Internal/ReturnType/CallbackReturnTypeFactory.cs new file mode 100644 index 000000000..a5092d3bd --- /dev/null +++ b/src/Generation/Generator3/Model/Internal/ReturnType/CallbackReturnTypeFactory.cs @@ -0,0 +1,33 @@ +namespace Generator3.Model.Internal +{ + public static class CallbackReturnTypeFactory + { + public static ReturnType CreateInternalModelForCallback(this GirModel.ReturnType returnValue) => returnValue.AnyType.Match( + type => type switch + { + GirModel.PrimitiveValueType => new PrimitiveValueReturnType(returnValue), + GirModel.Bitfield => new BitfieldReturnType(returnValue), + GirModel.Enumeration => new EnumerationReturnType(returnValue), + GirModel.Utf8String => new Utf8StringReturnType(returnValue), + GirModel.PlatformString => new PlatformStringReturnType(returnValue), + GirModel.Record => new RecordReturnTypeForCallback(returnValue), + GirModel.Union => new UnionReturnType(returnValue), + GirModel.Class => new ClassReturnType(returnValue), + GirModel.Interface => new InterfaceReturnType(returnValue), + GirModel.Pointer => new PointerReturnType(returnValue), + _ => new StandardReturnType(returnValue) + }, + arrayType => arrayType.AnyType.Match( + type => type switch + { + GirModel.String => new ArrayStringReturnType(returnValue), + GirModel.Record => new ArrayRecordReturnType(returnValue), + GirModel.Class => new ArrayClassReturnType(returnValue), + GirModel.PrimitiveValueType => new ArrayPrimitiveValueReturnType(returnValue), + _ => new StandardReturnType(returnValue) + }, + _ => new StandardReturnType(returnValue) + ) + ); + } +} diff --git a/src/Generation/Generator3/Model/Internal/ReturnType/RecordReturnType.cs b/src/Generation/Generator3/Model/Internal/ReturnType/RecordReturnType.cs index ec8598015..548a9ae39 100644 --- a/src/Generation/Generator3/Model/Internal/ReturnType/RecordReturnType.cs +++ b/src/Generation/Generator3/Model/Internal/ReturnType/RecordReturnType.cs @@ -1,4 +1,5 @@ using Generator3.Converter; +using GirModel; namespace Generator3.Model.Internal { @@ -6,9 +7,11 @@ public class RecordReturnType : ReturnType { private GirModel.Record Type => (GirModel.Record) Model.AnyType.AsT0; - public override string NullableTypeName => IsPointer - ? Type.GetFullyQualifiedInternalHandle() - : Type.GetFullyQualifiedInternalStructName(); + public override string NullableTypeName => !IsPointer + ? Type.GetFullyQualifiedInternalStructName() + : Model.Transfer == Transfer.None + ? Type.GetFullyQualifiedInternalUnownedHandle() + : Type.GetFullyQualifiedInternalOwnedHandle(); protected internal RecordReturnType(GirModel.ReturnType returnValue) : base(returnValue) { diff --git a/src/Generation/Generator3/Model/Internal/ReturnType/RecordReturnTypeForCallback.cs b/src/Generation/Generator3/Model/Internal/ReturnType/RecordReturnTypeForCallback.cs new file mode 100644 index 000000000..b8bfe89cf --- /dev/null +++ b/src/Generation/Generator3/Model/Internal/ReturnType/RecordReturnTypeForCallback.cs @@ -0,0 +1,19 @@ +using Generator3.Converter; +using GirModel; + +namespace Generator3.Model.Internal +{ + public class RecordReturnTypeForCallback : ReturnType + { + private GirModel.Record Type => (GirModel.Record) Model.AnyType.AsT0; + + public override string NullableTypeName => !IsPointer + ? Type.GetFullyQualifiedInternalStructName() + : Type.GetFullyQualifiedInternalHandle(); + + protected internal RecordReturnTypeForCallback(GirModel.ReturnType returnValue) : base(returnValue) + { + returnValue.AnyType.VerifyType(); + } + } +} diff --git a/src/GirCore.Testing.props b/src/GirCore.Testing.props index 99210c22e..11fdb313a 100644 --- a/src/GirCore.Testing.props +++ b/src/GirCore.Testing.props @@ -5,10 +5,10 @@ - - - - + + + + diff --git a/src/Libs/GLib-2.0/Records/MainLoop.cs b/src/Libs/GLib-2.0/Records/MainLoop.cs index 107756461..f94a367df 100644 --- a/src/Libs/GLib-2.0/Records/MainLoop.cs +++ b/src/Libs/GLib-2.0/Records/MainLoop.cs @@ -5,7 +5,7 @@ public sealed partial class MainLoop public MainLoop(MainContext context, bool isRunning = false) : this(context.Handle, isRunning) { } - public MainLoop() : this(Internal.MainContextHandle.Null, false) { } + public MainLoop() : this(Internal.MainContextNullHandle.Instance, false) { } private MainLoop(Internal.MainContextHandle context, bool isRunning) { diff --git a/src/Libs/GLib-2.0/Records/Variant.cs b/src/Libs/GLib-2.0/Records/Variant.cs index e336c7f9c..b148a2a9f 100644 --- a/src/Libs/GLib-2.0/Records/Variant.cs +++ b/src/Libs/GLib-2.0/Records/Variant.cs @@ -94,6 +94,6 @@ public void Dispose() public static class VariantExtension { public static VariantHandle GetSafeHandle(this Variant? variant) - => variant is null ? VariantHandle.Null : variant.Handle; + => variant is null ? VariantNullHandle.Instance : variant.Handle; } } diff --git a/src/Libs/GObject-2.0/Internal/Classes/ObjectWrapper.cs b/src/Libs/GObject-2.0/Internal/Classes/ObjectWrapper.cs index 04e0cc40d..e02854a3e 100644 --- a/src/Libs/GObject-2.0/Internal/Classes/ObjectWrapper.cs +++ b/src/Libs/GObject-2.0/Internal/Classes/ObjectWrapper.cs @@ -37,7 +37,7 @@ public static T WrapHandle(IntPtr handle, bool ownedRef) where T : class, IHa Type gtype = GetTypeFromInstance(handle); Debug.Assert( - condition: Marshal.PtrToStringUTF8(Functions.TypeName(gtype.Value)) == Marshal.PtrToStringUTF8(Functions.TypeNameFromInstance(new TypeInstanceHandle(handle, false))), + condition: Marshal.PtrToStringUTF8(Functions.TypeName(gtype.Value)) == Marshal.PtrToStringUTF8(Functions.TypeNameFromInstance(new TypeInstanceUnownedHandle(handle))), message: "GType name of instance and class do not match" ); diff --git a/src/Libs/Gdk-3.0/Records/Event.cs b/src/Libs/Gdk-3.0/Records/Event.cs index e23b23b2d..afc41fb59 100644 --- a/src/Libs/Gdk-3.0/Records/Event.cs +++ b/src/Libs/Gdk-3.0/Records/Event.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using Gdk.Internal; namespace Gdk { @@ -14,67 +15,109 @@ public static Event FromPointer(IntPtr ptr, bool ownsHandle) var ev = Marshal.PtrToStructure(ptr); switch (ev.Type) { - case EventType.Expose: - return new EventExpose(ptr, ownsHandle); case EventType.VisibilityNotify: - return new EventVisibility(ptr, ownsHandle); + return ownsHandle + ? new EventVisibility(new EventVisibilityOwnedHandle(ptr)) + : new EventVisibility(new EventVisibilityUnownedHandle(ptr)); case EventType.MotionNotify: - return new EventMotion(ptr, ownsHandle); + return ownsHandle + ? new EventMotion(new EventMotionOwnedHandle(ptr)) + : new EventMotion(new EventMotionUnownedHandle(ptr)); case EventType.ButtonPress: case EventType.TwoButtonPress: case EventType.ThreeButtonPress: case EventType.ButtonRelease: - return new EventButton(ptr, ownsHandle); + return ownsHandle + ? new EventButton(new EventButtonOwnedHandle(ptr)) + : new EventButton(new EventButtonUnownedHandle(ptr)); case EventType.TouchBegin: - return new EventTouch(ptr, ownsHandle); + return ownsHandle + ? new EventTouch(new EventTouchOwnedHandle(ptr)) + : new EventTouch(new EventTouchUnownedHandle(ptr)); case EventType.Scroll: - return new EventScroll(ptr, ownsHandle); + return ownsHandle + ? new EventScroll(new EventScrollOwnedHandle(ptr)) + : new EventScroll(new EventScrollUnownedHandle(ptr)); case EventType.KeyPress: case EventType.KeyRelease: - return new EventKey(ptr, ownsHandle); + return ownsHandle + ? new EventKey(new EventKeyOwnedHandle(ptr)) + : new EventKey(new EventKeyUnownedHandle(ptr)); case EventType.EnterNotify: case EventType.LeaveNotify: - return new EventCrossing(ptr, ownsHandle); + return ownsHandle + ? new EventCrossing(new EventCrossingOwnedHandle(ptr)) + : new EventCrossing(new EventCrossingUnownedHandle(ptr)); case EventType.FocusChange: - return new EventFocus(ptr, ownsHandle); + return ownsHandle + ? new EventFocus(new EventFocusOwnedHandle(ptr)) + : new EventFocus(new EventFocusUnownedHandle(ptr)); case EventType.Configure: - return new EventConfigure(ptr, ownsHandle); + return ownsHandle + ? new EventConfigure(new EventConfigureOwnedHandle(ptr)) + : new EventConfigure(new EventConfigureUnownedHandle(ptr)); case EventType.PropertyNotify: - return new EventProperty(ptr, ownsHandle); + return ownsHandle + ? new EventProperty(new EventPropertyOwnedHandle(ptr)) + : new EventProperty(new EventPropertyUnownedHandle(ptr)); case EventType.SelectionClear: case EventType.SelectionNotify: case EventType.SelectionRequest: - return new EventSelection(ptr, ownsHandle); + return ownsHandle + ? new EventSelection(new EventSelectionOwnedHandle(ptr)) + : new EventSelection(new EventSelectionUnownedHandle(ptr)); case EventType.OwnerChange: - return new EventOwnerChange(ptr, ownsHandle); + return ownsHandle + ? new EventOwnerChange(new EventOwnerChangeOwnedHandle(ptr)) + : new EventOwnerChange(new EventOwnerChangeUnownedHandle(ptr)); case EventType.ProximityIn: case EventType.ProximityOut: - return new EventProximity(ptr, ownsHandle); + return ownsHandle + ? new EventProximity(new EventProximityOwnedHandle(ptr)) + : new EventProximity(new EventProximityUnownedHandle(ptr)); case EventType.DragEnter: case EventType.DragLeave: case EventType.DragMotion: case EventType.DragStatus: case EventType.DropStart: case EventType.DropFinished: - return new EventDND(ptr, ownsHandle); + return ownsHandle + ? new EventDND(new EventDNDOwnedHandle(ptr)) + : new EventDND(new EventDNDUnownedHandle(ptr)); case EventType.WindowState: - return new EventWindowState(ptr, ownsHandle); + return ownsHandle + ? new EventWindowState(new EventWindowStateOwnedHandle(ptr)) + : new EventWindowState(new EventWindowStateUnownedHandle(ptr)); case EventType.Setting: - return new EventSetting(ptr, ownsHandle); + return ownsHandle + ? new EventSetting(new EventSettingOwnedHandle(ptr)) + : new EventSetting(new EventSettingUnownedHandle(ptr)); case EventType.GrabBroken: - return new EventGrabBroken(ptr, ownsHandle); + return ownsHandle + ? new EventGrabBroken(new EventGrabBrokenOwnedHandle(ptr)) + : new EventGrabBroken(new EventGrabBrokenUnownedHandle(ptr)); case EventType.TouchpadSwipe: - return new EventTouchpadSwipe(ptr, ownsHandle); + return ownsHandle + ? new EventTouchpadSwipe(new EventTouchpadSwipeOwnedHandle(ptr)) + : new EventTouchpadSwipe(new EventTouchpadSwipeUnownedHandle(ptr)); case EventType.TouchpadPinch: - return new EventTouchpadPinch(ptr, ownsHandle); + return ownsHandle + ? new EventTouchpadPinch(new EventTouchpadPinchOwnedHandle(ptr)) + : new EventTouchpadPinch(new EventTouchpadPinchUnownedHandle(ptr)); case EventType.PadButtonPress: case EventType.PadButtonRelease: - return new EventPadButton(ptr, ownsHandle); + return ownsHandle + ? new EventPadButton(new EventPadButtonOwnedHandle(ptr)) + : new EventPadButton(new EventPadButtonUnownedHandle(ptr)); case EventType.PadRing: case EventType.PadStrip: - return new EventPadAxis(ptr, ownsHandle); + return ownsHandle + ? new EventPadAxis(new EventPadAxisOwnedHandle(ptr)) + : new EventPadAxis(new EventPadAxisUnownedHandle(ptr)); case EventType.PadGroupMode: - return new EventPadGroupMode(ptr, ownsHandle); + return ownsHandle + ? new EventPadGroupMode(new EventPadGroupModeOwnedHandle(ptr)) + : new EventPadGroupMode(new EventPadGroupModeUnownedHandle(ptr)); // Default/Not Implemented case EventType.Map: case EventType.Unmap: diff --git a/src/Libs/Gio-2.0/Classes/DBusConnection.cs b/src/Libs/Gio-2.0/Classes/DBusConnection.cs index 56c26973d..40321ba31 100644 --- a/src/Libs/Gio-2.0/Classes/DBusConnection.cs +++ b/src/Libs/Gio-2.0/Classes/DBusConnection.cs @@ -43,15 +43,15 @@ void Callback(GObject.Object sourceObject, AsyncResult res) //TODO: Use on time CallbackHandler _callAsyncCallbackHandler = new AsyncReadyCallbackAsyncHandler(Callback); - Internal.DBusConnection.Call(Handle, busName, objectPath, interfaceName, methodName, parameters.GetSafeHandle(), GLib.Internal.VariantTypeHandle.Null, DBusCallFlags.None, -1, IntPtr.Zero, _callAsyncCallbackHandler.NativeCallback, IntPtr.Zero); + Internal.DBusConnection.Call(Handle, busName, objectPath, interfaceName, methodName, parameters.GetSafeHandle(), GLib.Internal.VariantTypeNullHandle.Instance, DBusCallFlags.None, -1, IntPtr.Zero, _callAsyncCallbackHandler.NativeCallback, IntPtr.Zero); return tcs.Task; } public Variant Call(string busName, string objectPath, string interfaceName, string methodName, Variant? parameters = null) { - var parameterHandle = parameters?.Handle ?? GLib.Internal.VariantHandle.Null; - var ret = Internal.DBusConnection.CallSync(Handle, busName, objectPath, interfaceName, methodName, parameterHandle, GLib.Internal.VariantTypeHandle.Null, DBusCallFlags.None, 9999, IntPtr.Zero, out var error); + var parameterHandle = parameters?.Handle ?? GLib.Internal.VariantNullHandle.Instance; + var ret = Internal.DBusConnection.CallSync(Handle, busName, objectPath, interfaceName, methodName, parameterHandle, GLib.Internal.VariantTypeNullHandle.Instance, DBusCallFlags.None, 9999, IntPtr.Zero, out var error); Error.ThrowOnError(error); diff --git a/src/Libs/Gtk-3.0/Classes/TreeSelection.cs b/src/Libs/Gtk-3.0/Classes/TreeSelection.cs index aa9ead752..9c822e555 100644 --- a/src/Libs/Gtk-3.0/Classes/TreeSelection.cs +++ b/src/Libs/Gtk-3.0/Classes/TreeSelection.cs @@ -6,7 +6,7 @@ public partial class TreeSelection { public void GetSelected(out TreeModel model, out TreeIter iter) { - var iterHandle = Internal.TreeIterHandle.Null; + var iterHandle = Internal.TreeIterNullHandle.Instance; Internal.TreeSelection.GetSelected(Handle, out var modelPtr, iterHandle); model = ObjectWrapper.WrapHandle(modelPtr, false); diff --git a/src/Tests/Libs/GLib-2.0.Tests/Records/UnownedHandleTest.cs b/src/Tests/Libs/GLib-2.0.Tests/Records/UnownedHandleTest.cs new file mode 100644 index 000000000..fe9528a96 --- /dev/null +++ b/src/Tests/Libs/GLib-2.0.Tests/Records/UnownedHandleTest.cs @@ -0,0 +1,35 @@ +using System; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace GLib.Tests +{ + [TestClass, TestCategory("IntegrationTest")] + public class MemoryManagementTest + { + [TestMethod] + public void UnownedHandleIsNotFreed() + { + CollectAfter(() => Dir.Open("..", 0)); + + // Dir.Open creates a handle to a directory. + // This handle does not transfer ownership. This + // means we are not allowed to free the handle. + // There is no method to free the handle, for this + // reason we throw an exception if the handle is + // tried to be freed. + + // The "CollectAfter" method ensures that the garbage collector + // frees this handle as it is not used anymore. If the handle + // would get freed, the exception would be raised and the + // unit test would fail. + } + + private static void CollectAfter(Action action) + { + action(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + } +}