From e101e5c1abbfe241acc9f8bafd18190d7921e818 Mon Sep 17 00:00:00 2001 From: badcel <1218031+badcel@users.noreply.github.com> Date: Thu, 5 Sep 2024 18:29:01 +0200 Subject: [PATCH] Support class based safe handles --- .github/actions/create/action.yml | 3 +- docs/docs/faq.md | 25 +++++ src/Generation/Generator/Classes.cs | 1 + .../Generator/Internal/ClassHandle.cs | 32 ++++++ .../Generator/Public/Class/ClassFramework.cs | 3 + .../Public/Interface/InterfaceFramework.cs | 26 ----- src/Generation/Generator/Interfaces.cs | 1 - src/Generation/Generator/Model/Class.cs | 24 ++++ .../Internal/Callback/CallbackCallHandler.cs | 2 +- .../Renderer/Internal/Class/ClassHandle.cs | 101 +++++++++++++++++ .../Internal/{ => Class}/ClassMethods.cs | 0 .../Internal/{ => Class}/ClassStruct.cs | 0 .../Framework/FrameworkTypeRegistration.cs | 35 ++++-- .../Converter/Class.cs | 8 +- .../Converter/Interface.cs | 2 +- .../Converter/Class.cs | 4 +- .../Converter/Interface.cs | 4 +- .../Renderer/Public/Class/ClassFramework.cs | 48 ++------ .../Renderer/Public/Class/ClassFunctions.cs | 32 +++++- ...assInterfacePropertiesRenderer.Accessor.cs | 4 +- .../ClassPropertiesRenderer.Accessor.cs | 4 +- .../Public/Constructor/Converter/Class.cs | 2 +- .../Renderer/Public/ForeignTypedRecord.cs | 27 +++-- .../Converter/Class.cs | 9 +- .../Converter/Interface.cs | 2 +- .../Converter/Pointer.cs | 2 +- .../Public/Interface/InterfaceFramework.cs | 40 ------- .../Public/Interface/InterfaceProperties.cs | 5 + .../InterfaceImplementationFramework.cs | 9 +- .../InterfaceImplementationProperties.cs | 4 +- .../Renderer/Public/OpaqueTypedRecord.cs | 27 +++-- .../Converter/Class.cs | 43 +++++++- .../Converter/ClassArray.cs | 2 +- .../Converter/Interface.cs | 8 +- .../Converter/InterfaceArray.cs | 2 +- .../Converter/Class.cs | 5 +- .../Converter/Interface.cs | 4 +- .../Generator/Renderer/Public/TypedRecord.cs | 27 +++-- src/GirCore.Libs.slnf | 1 - src/GirCore.sln | 24 +--- src/Libs/Adw-1/Public/Module.cs | 7 +- .../GObject}/Public/GTypeProvider.cs | 2 - .../GObject/Public/InstanceFactory.cs | 8 ++ src/Libs/GLib-2.0/Public/IHandle.cs | 8 -- src/Libs/GObject-2.0/Internal/BoxedWrapper.cs | 33 +----- .../GObject-2.0/Internal/CreateInstance.cs | 5 + .../Internal/DynamicInstanceFactory.cs | 57 ++++++++++ src/Libs/GObject-2.0/Internal/Functions.cs | 4 +- .../Internal/GTypeProviderHelper.cs | 20 ---- .../GObject-2.0/Internal/InstanceCache.cs | 76 +++++++++++++ .../GObject-2.0/Internal/InstanceWrapper.cs | 24 ++++ src/Libs/GObject-2.0/Internal/ObjectHandle.cs | 61 ++++++++++- .../Internal/ObjectMapper.ToggleRef.cs | 81 -------------- .../ObjectMapper.ToggleRegistration.cs | 32 ------ src/Libs/GObject-2.0/Internal/ObjectMapper.cs | 77 ------------- .../GObject-2.0/Internal/ObjectWrapper.cs | 103 ------------------ .../GObject-2.0/Internal/SubclassRegistrar.cs | 77 +++++++++++++ src/Libs/GObject-2.0/Internal/ToggleRef.cs | 46 ++++++++ .../Internal/ToggleRegistration.cs | 28 +++++ .../GObject-2.0/Internal/TypeDictionary.cs | 99 ----------------- .../GObject-2.0/Internal/TypeRegistrar.cs | 72 ------------ .../Internal/TypeRegistrationException.cs | 11 ++ .../GObject-2.0/Public/AssemblyExtension.cs | 2 +- src/Libs/GObject-2.0/Public/Closure.cs | 1 - .../GObject-2.0/Public/ConstructArgument.cs | 12 +- src/Libs/GObject-2.0/Public/IObject.cs | 9 -- .../GObject-2.0/Public/Object.Registration.cs | 58 ---------- src/Libs/GObject-2.0/Public/Object.Signals.cs | 6 +- src/Libs/GObject-2.0/Public/Object.cs | 71 ++---------- src/Libs/GObject-2.0/Public/Property.cs | 2 +- .../Public/ReturningSignalTSender.cs | 4 - .../ReturningSignalTSenderTSignalArgs.cs | 4 - src/Libs/GObject-2.0/Public/SignalTSender.cs | 4 - .../Public/SignalTSenderTSignalArgs.cs | 4 - src/Libs/GObject-2.0/Public/Value.cs | 1 - src/Libs/Gdk-4.0/Public/Clipboard.cs | 4 +- .../GdkPixbuf-2.0/Internal/PixbufHandle.cs | 19 ++++ src/Libs/GdkPixbuf-2.0/Public/Pixbuf.cs | 26 ----- src/Libs/GdkPixbuf-2.0/Public/PixbufLoader.cs | 33 ------ src/Libs/Gio-2.0/Public/DBusConnection.cs | 6 +- src/Libs/Gio-2.0/Public/Module.cs | 7 +- src/Libs/Gtk-4.0/Public/AlertDialog.cs | 6 +- src/Libs/Gtk-4.0/Public/Builder.cs | 31 +----- src/Libs/Gtk-4.0/Public/FileDialog.cs | 44 ++++---- src/Libs/Gtk-4.0/Public/FileLauncher.cs | 12 +- src/Libs/Gtk-4.0/Public/FontDialog.cs | 48 ++++---- src/Libs/Gtk-4.0/Public/Module.cs | 5 + src/Libs/Gtk-4.0/Public/UriLauncher.cs | 6 +- src/Libs/WebKit-6.0/Public/WebView.cs | 6 +- .../data/girtest-executor-private-impl.c | 42 +++++++ .../data/girtest-executor-private-impl.h | 13 +++ .../GirTestLib/girtest-property-tester.c | 47 +++++++- src/Native/GirTestLib/girtest.h | 1 + src/Native/GirTestLib/meson.build | 14 ++- src/Properties/GirCore.Libraries.props | 2 +- src/Properties/GirCore.Tooling.props | 2 +- src/Samples/Adw-1/Window/Window.csproj | 2 +- .../GdkPixbuf-2.0/TestLoading/Program.cs | 22 ---- .../TestLoading/TestLoading.csproj | 16 --- .../GdkPixbuf-2.0/TestLoading/test.bmp | Bin 750054 -> 0 bytes .../GdkPixbuf-2.0/TestMemoryLeaks/Program.cs | 18 ++- .../TestMemoryLeaks/TestMemoryLeaks.csproj | 2 +- src/Samples/Gio-2.0/DBus/DBus.csproj | 2 +- .../VideoPlayback/VideoPlayback.csproj | 2 +- .../Gtk-4.0/AboutDialog/AboutDialog.csproj | 2 +- .../Gtk-4.0/AboutDialog/SampleAboutDialog.cs | 10 +- src/Samples/Gtk-4.0/Builder/Builder.csproj | 2 +- .../Gtk-4.0/Builder/SampleTestDialog.cs | 14 +-- .../Gtk-4.0/DrawingArea/DrawingArea.csproj | 2 +- .../Gtk-4.0/FontDialog/FontDialog.csproj | 2 +- .../GridView/CustomObjectGridViewWindow.cs | 23 +++- src/Samples/Gtk-4.0/GridView/GridView.csproj | 2 +- .../GridView/StringListGridViewWindow.cs | 2 +- src/Samples/Gtk-4.0/ListView/ListView.csproj | 2 +- .../ListView/TemplateListViewWindow.cs | 2 +- src/Samples/Gtk-4.0/Window/Window.csproj | 2 +- .../GtkSourceView/GtkSourceView.csproj | 2 +- .../JavascriptCall/JavascriptCall.csproj | 2 +- .../JavascriptCallback.csproj | 2 +- src/Tests/Directory.Build.props | 8 -- src/Tests/Generation/Directory.Build.props | 8 ++ .../GirLoader.Tests/GirLoader.Tests.csproj | 2 +- src/Tests/Libs/Directory.Build.props | 8 ++ .../Classes/GenericTypeRegistrationTests.cs | 41 +++++-- .../GObject-2.0.Tests/Records/TypeTest.cs | 4 +- .../Libs/Gio-2.0.Tests/DBusConnectionTest.cs | 15 --- .../Libs/GirTest-0.1.Tests/CallbackTest.cs | 7 +- src/Tests/Libs/GirTest-0.1.Tests/ClassTest.cs | 16 +-- .../OpaqueTypedRecordTest.cs | 2 +- .../Libs/GirTest-0.1.Tests/PropertyTest.cs | 44 +++++++- .../Libs/GirTest-0.1.Tests/TypedRecordTest.cs | 2 +- src/Tests/Libs/Gtk-4.0.Tests/PropertyTests.cs | 13 --- 132 files changed, 1192 insertions(+), 1198 deletions(-) create mode 100644 src/Generation/Generator/Generator/Internal/ClassHandle.cs delete mode 100644 src/Generation/Generator/Generator/Public/Interface/InterfaceFramework.cs create mode 100644 src/Generation/Generator/Renderer/Internal/Class/ClassHandle.cs rename src/Generation/Generator/Renderer/Internal/{ => Class}/ClassMethods.cs (100%) rename src/Generation/Generator/Renderer/Internal/{ => Class}/ClassStruct.cs (100%) delete mode 100644 src/Generation/Generator/Renderer/Public/Interface/InterfaceFramework.cs rename src/Libs/{GObject-2.0 => GLib-2.0/GObject}/Public/GTypeProvider.cs (76%) create mode 100644 src/Libs/GLib-2.0/GObject/Public/InstanceFactory.cs delete mode 100644 src/Libs/GLib-2.0/Public/IHandle.cs create mode 100644 src/Libs/GObject-2.0/Internal/CreateInstance.cs create mode 100644 src/Libs/GObject-2.0/Internal/DynamicInstanceFactory.cs delete mode 100644 src/Libs/GObject-2.0/Internal/GTypeProviderHelper.cs create mode 100644 src/Libs/GObject-2.0/Internal/InstanceCache.cs create mode 100644 src/Libs/GObject-2.0/Internal/InstanceWrapper.cs delete mode 100644 src/Libs/GObject-2.0/Internal/ObjectMapper.ToggleRef.cs delete mode 100644 src/Libs/GObject-2.0/Internal/ObjectMapper.ToggleRegistration.cs delete mode 100644 src/Libs/GObject-2.0/Internal/ObjectMapper.cs delete mode 100644 src/Libs/GObject-2.0/Internal/ObjectWrapper.cs create mode 100644 src/Libs/GObject-2.0/Internal/SubclassRegistrar.cs create mode 100644 src/Libs/GObject-2.0/Internal/ToggleRef.cs create mode 100644 src/Libs/GObject-2.0/Internal/ToggleRegistration.cs delete mode 100644 src/Libs/GObject-2.0/Internal/TypeDictionary.cs delete mode 100644 src/Libs/GObject-2.0/Internal/TypeRegistrar.cs create mode 100644 src/Libs/GObject-2.0/Internal/TypeRegistrationException.cs delete mode 100644 src/Libs/GObject-2.0/Public/IObject.cs delete mode 100644 src/Libs/GObject-2.0/Public/Object.Registration.cs create mode 100644 src/Libs/GdkPixbuf-2.0/Internal/PixbufHandle.cs delete mode 100644 src/Libs/GdkPixbuf-2.0/Public/Pixbuf.cs delete mode 100644 src/Libs/GdkPixbuf-2.0/Public/PixbufLoader.cs create mode 100644 src/Native/GirTestLib/data/girtest-executor-private-impl.c create mode 100644 src/Native/GirTestLib/data/girtest-executor-private-impl.h delete mode 100644 src/Samples/GdkPixbuf-2.0/TestLoading/Program.cs delete mode 100644 src/Samples/GdkPixbuf-2.0/TestLoading/TestLoading.csproj delete mode 100644 src/Samples/GdkPixbuf-2.0/TestLoading/test.bmp delete mode 100644 src/Tests/Directory.Build.props create mode 100644 src/Tests/Generation/Directory.Build.props create mode 100644 src/Tests/Libs/Directory.Build.props delete mode 100644 src/Tests/Libs/Gio-2.0.Tests/DBusConnectionTest.cs diff --git a/.github/actions/create/action.yml b/.github/actions/create/action.yml index d899c3399..3811663ce 100644 --- a/.github/actions/create/action.yml +++ b/.github/actions/create/action.yml @@ -19,9 +19,8 @@ runs: uses: actions/setup-dotnet@v4 with: dotnet-version: | - 6.0.x - 7.0.x 8.0.x + 9.0.x - name: Compile native library run: dotnet fsi GenerateGirTestLib.fsx diff --git a/docs/docs/faq.md b/docs/docs/faq.md index fcabe314b..050f629a8 100644 --- a/docs/docs/faq.md +++ b/docs/docs/faq.md @@ -51,4 +51,29 @@ Gtk.Button.LabelPropertyDefinition.Notify( sender: myButton, signalHandler: OnButtonLabelChanged ); +``` + +## How to create subclasses of a GObject based class? +Creating a subclass for a GObject based class is a bit more complex than for a regular C# class. The reason for this is that the GObject type system is working in parallel to the C# type system. For a subclass to be known to the GObject type system it must be registered first. To be able to create an instance of a GObject based class every type must not only be registered but also implement some interfaces to allow seamless integration into the GObject type system: + +1. Implement GTypeProvider interface. This allows to get the GObject Type of the class during runtime. +2. Implement InstanceFactory interface. This allows to create an instance of the class during runtime for a given pointer. + +```csharp +public class Data : GObject.Object, GTypeProvider, InstanceFactory +{ + private static readonly Type GType = SubclassRegistrar.Register(); + public static new Type GetGType() => GType; + static object InstanceFactory.Create(IntPtr handle, bool ownsHandle) + { + return new Data(handle, ownsHandle); + } + + + public Data() : base(ObjectHandle.For(true, [])) + { + } + + private Data(IntPtr ptr, bool ownsHandle) : base(new ObjectHandle(ptr, ownsHandle)) { } +} ``` \ No newline at end of file diff --git a/src/Generation/Generator/Classes.cs b/src/Generation/Generator/Classes.cs index 2db0b8115..a8cd94c35 100644 --- a/src/Generation/Generator/Classes.cs +++ b/src/Generation/Generator/Classes.cs @@ -20,6 +20,7 @@ public static void Generate(IEnumerable classes, string path) //Standard generators new Generator.Internal.ClassMethods(publisher), new Generator.Internal.ClassStruct(publisher), + new Generator.Internal.ClassHandle(publisher), new Generator.Public.ClassConstructors(publisher), new Generator.Public.ClassMethods(publisher), new Generator.Public.ClassFunctions(publisher), diff --git a/src/Generation/Generator/Generator/Internal/ClassHandle.cs b/src/Generation/Generator/Generator/Internal/ClassHandle.cs new file mode 100644 index 000000000..5e2cfc394 --- /dev/null +++ b/src/Generation/Generator/Generator/Internal/ClassHandle.cs @@ -0,0 +1,32 @@ +using Generator.Model; + +namespace Generator.Generator.Internal; + +internal class ClassHandle : Generator +{ + private readonly Publisher _publisher; + + public ClassHandle(Publisher publisher) + { + _publisher = publisher; + } + + public void Generate(GirModel.Class obj) + { + if (obj.Fundamental) + return; + + if (obj.Parent is null) + return; //Do not generate a handle for GObject.Object itself + + var source = Renderer.Internal.ClassHandle.Render(obj); + var codeUnit = new CodeUnit( + Project: Namespace.GetCanonicalName(obj.Namespace), + Name: Class.GetInternalHandleName(obj), + Source: source, + IsInternal: true + ); + + _publisher.Publish(codeUnit); + } +} diff --git a/src/Generation/Generator/Generator/Public/Class/ClassFramework.cs b/src/Generation/Generator/Generator/Public/Class/ClassFramework.cs index 7e883efcb..d3b4a2185 100644 --- a/src/Generation/Generator/Generator/Public/Class/ClassFramework.cs +++ b/src/Generation/Generator/Generator/Public/Class/ClassFramework.cs @@ -16,6 +16,9 @@ public void Generate(GirModel.Class obj) if (obj.Fundamental) return; + if (obj.Parent is null) + return; //Do not generate Framework for GObject.Object itself + var source = Renderer.Public.ClassFramework.Render(obj); var codeUnit = new CodeUnit( Project: Namespace.GetCanonicalName(obj.Namespace), diff --git a/src/Generation/Generator/Generator/Public/Interface/InterfaceFramework.cs b/src/Generation/Generator/Generator/Public/Interface/InterfaceFramework.cs deleted file mode 100644 index 89b4241e1..000000000 --- a/src/Generation/Generator/Generator/Public/Interface/InterfaceFramework.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Generator.Model; - -namespace Generator.Generator.Public; - -internal class InterfaceFramework : Generator -{ - private readonly Publisher _publisher; - - public InterfaceFramework(Publisher publisher) - { - _publisher = publisher; - } - - public void Generate(GirModel.Interface obj) - { - var source = Renderer.Public.InterfaceFramework.Render(obj); - var codeUnit = new CodeUnit( - Project: Namespace.GetCanonicalName(obj.Namespace), - Name: $"{obj.Name}.Framework", - Source: source, - IsInternal: false - ); - - _publisher.Publish(codeUnit); - } -} diff --git a/src/Generation/Generator/Interfaces.cs b/src/Generation/Generator/Interfaces.cs index 4cfcc4c8f..8a4174499 100644 --- a/src/Generation/Generator/Interfaces.cs +++ b/src/Generation/Generator/Interfaces.cs @@ -11,7 +11,6 @@ public static void Generate(IEnumerable interfaces, string p var generators = new List>() { new Generator.Internal.InterfaceMethods(publisher), - new Generator.Public.InterfaceFramework(publisher), new Generator.Public.InterfaceMethods(publisher), new Generator.Public.InterfaceProperties(publisher), diff --git a/src/Generation/Generator/Model/Class.cs b/src/Generation/Generator/Model/Class.cs index d44d48a9a..74486388c 100644 --- a/src/Generation/Generator/Model/Class.cs +++ b/src/Generation/Generator/Model/Class.cs @@ -11,6 +11,18 @@ public static string GetFullyQualifiedInternalStructName(GirModel.Class @class) public static string GetInternalStructName(GirModel.Class @class) => @class.Name + "Data"; + public static string GetInternalHandleName(GirModel.Class @class) + => @class.Name + "Handle"; + + public static string GetFullyQualifiedInternalHandleName(GirModel.Class @class) + => Namespace.GetInternalName(@class.Namespace) + "." + GetInternalHandleName(@class); + + public static string GetFullyQualifiedPublicName(GirModel.Class @class) + => Namespace.GetPublicName(@class.Namespace) + "." + @class.Name; + + public static string GetFullyQualifiedInternalName(GirModel.Class @class) + => Namespace.GetInternalName(@class.Namespace) + "." + @class.Name; + public static bool HidesConstructor(GirModel.Class? cls, GirModel.Constructor constructor) { if (cls is null) @@ -84,4 +96,16 @@ private static bool ParameterMatch(GirModel.Parameter[] p1, GirModel.Parameter[] return true; } + + public static bool IsInitiallyUnowned(GirModel.Class cls) => IsNamedInitiallyUnowned(cls.Name) || InheritsInitiallyUnowned(cls); + + private static bool InheritsInitiallyUnowned(GirModel.Class @class) + { + if (@class.Parent is null) + return false; + + return IsNamedInitiallyUnowned(@class.Parent.Name) || InheritsInitiallyUnowned(@class.Parent); + } + + private static bool IsNamedInitiallyUnowned(string name) => name == "InitiallyUnowned"; } diff --git a/src/Generation/Generator/Renderer/Internal/Callback/CallbackCallHandler.cs b/src/Generation/Generator/Renderer/Internal/Callback/CallbackCallHandler.cs index ced3dfc4b..b0020bfbb 100644 --- a/src/Generation/Generator/Renderer/Internal/Callback/CallbackCallHandler.cs +++ b/src/Generation/Generator/Renderer/Internal/Callback/CallbackCallHandler.cs @@ -22,7 +22,7 @@ namespace {Namespace.GetInternalName(callback.Namespace)}; // AUTOGENERATED FILE - DO NOT MODIFY -// +/// /// Call Handler for {callback.Name}. A call annotation indicates the closure should /// be valid for the duration of the call. This handler does not implement any special /// memory management. diff --git a/src/Generation/Generator/Renderer/Internal/Class/ClassHandle.cs b/src/Generation/Generator/Renderer/Internal/Class/ClassHandle.cs new file mode 100644 index 000000000..a209af4fb --- /dev/null +++ b/src/Generation/Generator/Renderer/Internal/Class/ClassHandle.cs @@ -0,0 +1,101 @@ +using System; +using Generator.Model; + +namespace Generator.Renderer.Internal; + +internal static class ClassHandle +{ + public static string Render(GirModel.Class cls) + { + return cls.Final + ? RenderFinalClassHandle(cls) + : RenderStandardClassHandle(cls); + } + + private static string RenderFinalClassHandle(GirModel.Class cls) + { + var handleName = Class.GetInternalHandleName(cls); + + return $$""" + using System; + using System.Linq; + using System.Runtime.InteropServices; + using System.Runtime.Versioning; + + #nullable enable + + namespace {{Namespace.GetInternalName(cls.Namespace)}}; + + public partial class {{handleName}} : {{RenderParent(cls)}} + { + public {{handleName}}(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle){ } + + public static {{handleName}} Create(bool owned, GObject.ConstructArgument[] constructArguments) + { + // We can't check if a reference is floating via "g_object_is_floating" here + // as the function could be "lying" depending on the intent of framework writers. + // E.g. A Gtk.Window created via "g_object_new_with_properties" returns an unowned + // reference which is not marked as floating as the gtk toolkit "owns" it. + // For this reason we just delegate the problem to the caller and require a + // definition whether the ownership of the new object will be transferred to us or not. + + var ptr = GObject.Internal.Object.NewWithProperties( + objectType: {{Class.GetFullyQualifiedInternalName(cls)}}.GetGType(), + nProperties: (uint) constructArguments.Length, + names: constructArguments.Select(x => x.Name).ToArray(), + values: GObject.Internal.ValueArray2OwnedHandle.Create(constructArguments.Select(x => x.Value).ToArray()) + ); + + return new {{handleName}}(ptr, owned); + } + } + """; + } + + private static string RenderStandardClassHandle(GirModel.Class cls) + { + var handleName = Class.GetInternalHandleName(cls); + + return $$""" + using System; + using System.Linq; + using System.Runtime.InteropServices; + using System.Runtime.Versioning; + + #nullable enable + + namespace {{Namespace.GetInternalName(cls.Namespace)}}; + + public partial class {{handleName}} : {{RenderParent(cls)}} + { + public {{handleName}}(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle){ } + + public static new {{handleName}} For(bool owned, GObject.ConstructArgument[] constructArguments) where T : {{Class.GetFullyQualifiedPublicName(cls)}}, GObject.GTypeProvider + { + // We can't check if a reference is floating via "g_object_is_floating" here + // as the function could be "lying" depending on the intent of framework writers. + // E.g. A Gtk.Window created via "g_object_new_with_properties" returns an unowned + // reference which is not marked as floating as the gtk toolkit "owns" it. + // For this reason we just delegate the problem to the caller and require a + // definition whether the ownership of the new object will be transferred to us or not. + + var ptr = GObject.Internal.Object.NewWithProperties( + objectType: T.GetGType(), + nProperties: (uint) constructArguments.Length, + names: constructArguments.Select(x => x.Name).ToArray(), + values: GObject.Internal.ValueArray2OwnedHandle.Create(constructArguments.Select(x => x.Value).ToArray()) + ); + + return new {{handleName}}(ptr, owned); + } + } + """; + } + + private static string RenderParent(GirModel.Class cls) + { + return cls.Parent is null + ? throw new Exception("Class is missing parent") + : Class.GetFullyQualifiedInternalHandleName(cls.Parent); + } +} diff --git a/src/Generation/Generator/Renderer/Internal/ClassMethods.cs b/src/Generation/Generator/Renderer/Internal/Class/ClassMethods.cs similarity index 100% rename from src/Generation/Generator/Renderer/Internal/ClassMethods.cs rename to src/Generation/Generator/Renderer/Internal/Class/ClassMethods.cs diff --git a/src/Generation/Generator/Renderer/Internal/ClassStruct.cs b/src/Generation/Generator/Renderer/Internal/Class/ClassStruct.cs similarity index 100% rename from src/Generation/Generator/Renderer/Internal/ClassStruct.cs rename to src/Generation/Generator/Renderer/Internal/Class/ClassStruct.cs diff --git a/src/Generation/Generator/Renderer/Internal/Framework/FrameworkTypeRegistration.cs b/src/Generation/Generator/Renderer/Internal/Framework/FrameworkTypeRegistration.cs index 9047ca51e..b4982a2cf 100644 --- a/src/Generation/Generator/Renderer/Internal/Framework/FrameworkTypeRegistration.cs +++ b/src/Generation/Generator/Renderer/Internal/Framework/FrameworkTypeRegistration.cs @@ -15,6 +15,8 @@ public static string Render(GirModel.Namespace ns) using System.Diagnostics; using System.Linq; using System.Runtime.InteropServices; +using GObject; +using GObject.Internal; namespace {Namespace.GetInternalName(ns)}; @@ -29,6 +31,10 @@ internal static void RegisterTypes() .Select(RenderRegistration) .Join(Environment.NewLine)} + {ns.Interfaces + .Select(RenderInterfaceRegistration) + .Join(Environment.NewLine)} + {ns.Records .Where(record => record.TypeFunction is not null) .Select(RenderRegistration) @@ -40,24 +46,29 @@ internal static void RegisterTypes() .Join(Environment.NewLine)} }} - private static void Register(Func getType, params OSPlatform[] supportedPlatforms) where T : class + private static void Register(params OSPlatform[] supportedPlatforms) where T : InstanceFactory, GTypeProvider {{ - try - {{ + try + {{ if(supportedPlatforms.Any(RuntimeInformation.IsOSPlatform)) - GObject.Internal.TypeDictionary.Add(typeof(T), new GObject.Type(getType())); - }} - catch(System.Exception e) - {{ - Debug.WriteLine($""Could not register type '{{nameof(T)}}': {{e.Message}}""); - }} - }} + GObject.Internal.DynamicInstanceFactory.Register(T.GetGType(), T.Create); + }} + catch(System.Exception e) + {{ + Debug.WriteLine($""Could not register type: {{e.Message}}""); + }} + }} }}"; } private static string RenderRegistration(GirModel.ComplexType type) { - return @$"Register<{ComplexType.GetFullyQualified(type)}>(Internal.{type.Name}.{Function.GetGType}{RenderPlatforms(type as GirModel.PlatformDependent)});"; + return $"Register<{ComplexType.GetFullyQualified(type)}>({RenderPlatforms(type as GirModel.PlatformDependent)});"; + } + + private static string RenderInterfaceRegistration(GirModel.Interface type) + { + return $"Register<{Interface.GetFullyQualifiedImplementationName(type)}>({RenderPlatforms(type as GirModel.PlatformDependent)});"; } private static string RenderPlatforms(GirModel.PlatformDependent? platformDependent) @@ -76,6 +87,6 @@ private static string RenderPlatforms(GirModel.PlatformDependent? platformDepend if (platformDependent.SupportsWindows) statements.Add("OSPlatform.Windows"); - return ", " + string.Join(", ", statements); + return string.Join(", ", statements); } } diff --git a/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/Class.cs b/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/Class.cs index 422237dda..ed009858c 100644 --- a/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/Class.cs +++ b/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/Class.cs @@ -38,12 +38,14 @@ private static void Default(ParameterToManagedData parameterData) var parameterName = Model.Parameter.GetName(parameterData.Parameter); var callName = Model.Parameter.GetConvertedName(parameterData.Parameter); + var type = Model.ComplexType.GetFullyQualified(cls); + var wrapHandle = parameterData.Parameter.Nullable - ? "GObject.Internal.ObjectWrapper.WrapNullableHandle" - : "GObject.Internal.ObjectWrapper.WrapHandle"; + ? $"({type}?) GObject.Internal.InstanceWrapper.WrapNullableHandle" + : $"({type}) GObject.Internal.InstanceWrapper.WrapHandle"; parameterData.SetSignatureName(() => parameterName); - parameterData.SetExpression(() => $"var {callName} = {wrapHandle}<{Model.ComplexType.GetFullyQualified(cls)}>({parameterName}, {Model.Transfer.IsOwnedRef(parameterData.Parameter.Transfer).ToString().ToLower()});"); + parameterData.SetExpression(() => $"var {callName} = {wrapHandle}<{type}>({parameterName}, {Model.Transfer.IsOwnedRef(parameterData.Parameter.Transfer).ToString().ToLower()});"); parameterData.SetCallName(() => callName); } } diff --git a/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/Interface.cs b/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/Interface.cs index 9ba89fcd3..873e26cb8 100644 --- a/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/Interface.cs +++ b/src/Generation/Generator/Renderer/Internal/ParameterToManagedExpression/Converter/Interface.cs @@ -19,7 +19,7 @@ public void Initialize(ParameterToManagedData parameterData, IEnumerable signatureName); - parameterData.SetExpression(() => $"var {callName} = GObject.Internal.ObjectWrapper.WrapInterfaceHandle<{Model.Interface.GetFullyQualifiedImplementationName(iface)}>({signatureName}, {Model.Transfer.IsOwnedRef(parameterData.Parameter.Transfer).ToString().ToLower()});"); + parameterData.SetExpression(() => $"var {callName} = ({Model.Type.GetPublicNameFullyQuallified(iface)}) GObject.Internal.InstanceWrapper.WrapHandle<{Model.Interface.GetFullyQualifiedImplementationName(iface)}>({signatureName}, {Model.Transfer.IsOwnedRef(parameterData.Parameter.Transfer).ToString().ToLower()});"); parameterData.SetCallName(() => callName); } } diff --git a/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/Class.cs b/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/Class.cs index 28c2b0578..40658fa58 100644 --- a/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/Class.cs +++ b/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/Class.cs @@ -14,7 +14,7 @@ public string GetString(GirModel.ReturnType returnType, string fromVariableName) throw new NotImplementedException($"{returnType.AnyType}: class return type which is no pointer can not be converted to native"); return returnType.Nullable - ? fromVariableName + "?.Handle ?? IntPtr.Zero" - : fromVariableName + ".Handle"; + ? fromVariableName + "?.Handle.DangerousGetHandle() ?? IntPtr.Zero" + : fromVariableName + ".Handle.DangerousGetHandle()"; } } diff --git a/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/Interface.cs b/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/Interface.cs index f2445de21..3f42dc83b 100644 --- a/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/Interface.cs +++ b/src/Generation/Generator/Renderer/Internal/ReturnTypeToNativeExpression/Converter/Interface.cs @@ -8,7 +8,7 @@ public bool Supports(GirModel.AnyType type) public string GetString(GirModel.ReturnType returnType, string fromVariableName) { return returnType.Nullable - ? fromVariableName + "?.Handle ?? IntPtr.Zero" - : fromVariableName + ".Handle"; + ? fromVariableName + "?.Handle.DangerousGetHandle() ?? IntPtr.Zero" + : fromVariableName + ".Handle.DangerousGetHandle()"; } } diff --git a/src/Generation/Generator/Renderer/Public/Class/ClassFramework.cs b/src/Generation/Generator/Renderer/Public/Class/ClassFramework.cs index 0afbf52eb..20fd9f965 100644 --- a/src/Generation/Generator/Renderer/Public/Class/ClassFramework.cs +++ b/src/Generation/Generator/Renderer/Public/Class/ClassFramework.cs @@ -13,7 +13,6 @@ public static string Render(GirModel.Class cls) return $@" using System; -using GObject; using System.Runtime.InteropServices; using System.Runtime.Versioning; @@ -26,7 +25,8 @@ namespace {Namespace.GetPublicName(cls.Namespace)}; {PlatformSupportAttribute.Render(cls as GirModel.PlatformDependent)} public {@sealed}partial class {cls.Name} {RenderInheritance(cls)} {{ - {RenderParentConstructors(cls)} + {$"protected internal {cls.Name}({Class.GetFullyQualifiedInternalHandleName(cls)} handle) : base(handle) {{ }}"} + {RenderPublicConstructor(cls)} }}"; } @@ -45,46 +45,12 @@ private static string RenderInheritance(GirModel.Class cls) : $": {string.Join(", ", elements)}"; } - private static string RenderParentConstructors(GirModel.Class cls) + private static string RenderPublicConstructor(GirModel.Class cls) { - if (cls.Parent is null) - return string.Empty; + var owned = Class.IsInitiallyUnowned(cls) ? "false" : "true"; - var constructors = new List() - { - $@"protected internal { cls.Name }(IntPtr ptr, bool ownedRef) : base(ptr, ownedRef) {{}}", - }; - - if (IsInitiallyUnowned(cls)) - { - constructors.Add($@" -// As initially unowned objects always start with a floating reference -// we can safely set the ""owned"" parameter to false. -protected internal {cls.Name}(params ConstructArgument[] constructArguments) : base(owned: false, constructArguments) {{}}"); - constructors.Add($"public {cls.Name}() : this(Array.Empty()) {{}}"); - } - else if (InheritsInitiallyUnowned(cls)) - { - constructors.Add($"protected internal {cls.Name}(params ConstructArgument[] constructArguments) : base(constructArguments) {{}}"); - constructors.Add($"public {cls.Name}() : this(Array.Empty()) {{}}"); - } - else - { - constructors.Add($"protected internal {cls.Name}(bool owned, params ConstructArgument[] constructArguments) : base(owned, constructArguments) {{}}"); - } - - return constructors.Join(Environment.NewLine); - } - - private static bool IsInitiallyUnowned(GirModel.Class cls) => IsNamedInitiallyUnowned(cls.Name); - - private static bool InheritsInitiallyUnowned(GirModel.Class @class) - { - if (@class.Parent is null) - return false; - - return IsNamedInitiallyUnowned(@class.Parent.Name) || InheritsInitiallyUnowned(@class.Parent); + return cls.Final + ? $" public {cls.Name}() : this({Class.GetFullyQualifiedInternalHandleName(cls)}.Create({owned}, Array.Empty())) {{ }}" + : $" public {cls.Name}() : this({Class.GetFullyQualifiedInternalHandleName(cls)}.For<{cls.Name}>({owned}, Array.Empty())) {{ }}"; } - - private static bool IsNamedInitiallyUnowned(string name) => name == "InitiallyUnowned"; } diff --git a/src/Generation/Generator/Renderer/Public/Class/ClassFunctions.cs b/src/Generation/Generator/Renderer/Public/Class/ClassFunctions.cs index b1bfddcc7..121f4f17e 100644 --- a/src/Generation/Generator/Renderer/Public/Class/ClassFunctions.cs +++ b/src/Generation/Generator/Renderer/Public/Class/ClassFunctions.cs @@ -8,6 +8,10 @@ internal static class ClassFunctions { public static string Render(GirModel.Class cls) { + var newModifier = cls.Parent is null + ? string.Empty + : "new "; + return $@" using System; using System.Linq; @@ -20,13 +24,37 @@ namespace {Namespace.GetPublicName(cls.Namespace)}; // AUTOGENERATED FILE - DO NOT MODIFY -public partial class {cls.Name} : GObject.GTypeProvider +public partial class {cls.Name} : GObject.GTypeProvider, GObject.InstanceFactory {{ - {FunctionRenderer.Render(cls.TypeFunction)} + + public static {newModifier}GObject.Type GetGType() + {{ + return {RenderGetGType(cls.TypeFunction)}; + }} + + static object GObject.InstanceFactory.Create(IntPtr handle, bool ownsHandle) + {{ + return CreateIntern(handle, ownsHandle); + }} + + private static {cls.Name} CreateIntern(IntPtr handle, bool ownsHandle) + {{ + return {RenderObjectFactory(cls)}; + }} {cls.Functions .Select(FunctionRenderer.Render) .Join(Environment.NewLine)} }}"; } + + private static string RenderGetGType(GirModel.Function function) + { + return $"{Namespace.GetInternalName(function.Namespace)}.{function.Parent!.Name}.{Function.GetName(function)}()"; + } + + private static string RenderObjectFactory(GirModel.Class cls) + { + return $"new {cls.Name}(new {Class.GetFullyQualifiedInternalHandleName(cls)}(handle, ownsHandle))"; + } } diff --git a/src/Generation/Generator/Renderer/Public/Class/InterfaceProperties/ClassInterfacePropertiesRenderer.Accessor.cs b/src/Generation/Generator/Renderer/Public/Class/InterfaceProperties/ClassInterfacePropertiesRenderer.Accessor.cs index c8cf52628..df7bb41c9 100644 --- a/src/Generation/Generator/Renderer/Public/Class/InterfaceProperties/ClassInterfacePropertiesRenderer.Accessor.cs +++ b/src/Generation/Generator/Renderer/Public/Class/InterfaceProperties/ClassInterfacePropertiesRenderer.Accessor.cs @@ -36,14 +36,14 @@ private static string RenderAccessor(GirModel.Interface @interface, GirModel.Pro private static string GetGetter(GirModel.Interface @interface, GirModel.Property property) { return Property.SupportsAccessorGetMethod(property, out var getter) - ? $"{Namespace.GetInternalName(@interface.Namespace)}.{@interface.Name}.{Method.GetInternalName(getter)}(Handle)" + ? $"{Namespace.GetInternalName(@interface.Namespace)}.{@interface.Name}.{Method.GetInternalName(getter)}(Handle.DangerousGetHandle())" : $"{ComplexType.GetFullyQualified(@interface)}.{Property.GetDescriptorName(property)}.Get(this)"; } private static string GetSetter(GirModel.Interface @interface, GirModel.Property property) { return Property.SupportsAccessorSetMethod(property, out var setter) - ? $"{Namespace.GetInternalName(@interface.Namespace)}.{@interface.Name}.{Method.GetInternalName(setter)}(Handle, value)" + ? $"{Namespace.GetInternalName(@interface.Namespace)}.{@interface.Name}.{Method.GetInternalName(setter)}(Handle.DangerousGetHandle(), value)" : $"{ComplexType.GetFullyQualified(@interface)}.{Property.GetDescriptorName(property)}.Set(this, value)"; } } diff --git a/src/Generation/Generator/Renderer/Public/Class/Properties/ClassPropertiesRenderer.Accessor.cs b/src/Generation/Generator/Renderer/Public/Class/Properties/ClassPropertiesRenderer.Accessor.cs index 0edefbd33..468cd32ec 100644 --- a/src/Generation/Generator/Renderer/Public/Class/Properties/ClassPropertiesRenderer.Accessor.cs +++ b/src/Generation/Generator/Renderer/Public/Class/Properties/ClassPropertiesRenderer.Accessor.cs @@ -28,14 +28,14 @@ private static string RenderAccessor(GirModel.ComplexType complexType, GirModel. private static string GetGetter(GirModel.ComplexType complexType, GirModel.Property property) { return Property.SupportsAccessorGetMethod(property, out var getter) - ? $"{Namespace.GetInternalName(complexType.Namespace)}.{complexType.Name}.{Method.GetInternalName(getter)}(Handle)" + ? $"{Namespace.GetInternalName(complexType.Namespace)}.{complexType.Name}.{Method.GetInternalName(getter)}(base.Handle.DangerousGetHandle())" : $"{Property.GetDescriptorName(property)}.Get(this)"; } private static string GetSetter(GirModel.ComplexType complexType, GirModel.Property property) { return Property.SupportsAccessorSetMethod(property, out var setter) - ? $"{Namespace.GetInternalName(complexType.Namespace)}.{complexType.Name}.{Method.GetInternalName(setter)}(Handle, value)" + ? $"{Namespace.GetInternalName(complexType.Namespace)}.{complexType.Name}.{Method.GetInternalName(setter)}(base.Handle.DangerousGetHandle(), value)" : $"{Property.GetDescriptorName(property)}.Set(this, value)"; } } diff --git a/src/Generation/Generator/Renderer/Public/Constructor/Converter/Class.cs b/src/Generation/Generator/Renderer/Public/Constructor/Converter/Class.cs index dc190c18d..64b084472 100644 --- a/src/Generation/Generator/Renderer/Public/Constructor/Converter/Class.cs +++ b/src/Generation/Generator/Renderer/Public/Constructor/Converter/Class.cs @@ -24,6 +24,6 @@ private static string CreateExpression(GirModel.Constructor constructor, string return cls.Fundamental ? $"new {cls.Name}({fromVariableName})" - : $"new {cls.Name}({fromVariableName}, {ownedRef.ToString().ToLower()})"; + : $"{cls.Namespace.Name}.{cls.Name}.CreateIntern({fromVariableName}, {ownedRef.ToString().ToLower()})"; } } diff --git a/src/Generation/Generator/Renderer/Public/ForeignTypedRecord.cs b/src/Generation/Generator/Renderer/Public/ForeignTypedRecord.cs index e3531734c..3554b645d 100644 --- a/src/Generation/Generator/Renderer/Public/ForeignTypedRecord.cs +++ b/src/Generation/Generator/Renderer/Public/ForeignTypedRecord.cs @@ -24,31 +24,33 @@ namespace {Namespace.GetPublicName(record.Namespace)}; // AUTOGENERATED FILE - DO NOT MODIFY {PlatformSupportAttribute.Render(record as GirModel.PlatformDependent)} -public partial class {name} : GLib.BoxedRecord, IDisposable +public partial class {name} : GLib.BoxedRecord, GObject.GTypeProvider, GObject.InstanceFactory, IDisposable {{ public {internalHandleName} Handle {{ get; }} public {name}({internalHandleName} handle) {{ Handle = handle; - Initialize(); }} - //TODO: This is a workaround constructor as long as we are - //not having https://github.com/gircore/gir.core/issues/397 - private {name}(IntPtr ptr, bool ownsHandle) : this(ownsHandle - ? new {Model.ForeignTypedRecord.GetFullyQuallifiedOwnedHandle(record)}(ptr) - : new {Model.ForeignTypedRecord.GetFullyQuallifiedUnownedHandle(record)}(ptr).OwnedCopy()){{ }} + static object GObject.InstanceFactory.Create(IntPtr handle, bool ownsHandle) + {{ + var safeHandle = ownsHandle + ? new {Record.GetFullyQualifiedInternalOwnedHandle(record)}(handle) + : {Record.GetFullyQualifiedInternalOwnedHandle(record)}.FromUnowned(handle); - // Implement this to perform additional steps in the constructor - partial void Initialize(); + return new {name}(safeHandle); + }} System.IntPtr GLib.BoxedRecord.GetHandle() {{ return Handle.DangerousGetHandle(); }} - {FunctionRenderer.Render(record.TypeFunction)} + public static GObject.Type GetGType() + {{ + return {RenderGetGType(record.TypeFunction!)}; + }} public void Dispose() {{ @@ -56,4 +58,9 @@ public void Dispose() }} }}"; } + + private static string RenderGetGType(GirModel.Function function) + { + return $"{Namespace.GetInternalName(function.Namespace)}.{function.Parent!.Name}.{Function.GetName(function)}()"; + } } diff --git a/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/Class.cs b/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/Class.cs index b63b94d5c..941a67adf 100644 --- a/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/Class.cs +++ b/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/Class.cs @@ -9,6 +9,13 @@ public bool Supports(GirModel.Type type) public string GetExpression(GirModel.InstanceParameter instanceParameter) { - return "this.Handle"; + var cls = (GirModel.Class) instanceParameter.Type; + + if (cls.Fundamental) + return "this.Handle"; + + return cls.Parent is null + ? "this.Handle.DangerousGetHandle()" + : "base.Handle.DangerousGetHandle()"; } } diff --git a/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/Interface.cs b/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/Interface.cs index 67d3c54a4..f45347a5f 100644 --- a/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/Interface.cs +++ b/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/Interface.cs @@ -9,6 +9,6 @@ public bool Supports(GirModel.Type type) public string GetExpression(GirModel.InstanceParameter instanceParameter) { - return "this.Handle"; + return "this.Handle.DangerousGetHandle()"; } } diff --git a/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/Pointer.cs b/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/Pointer.cs index ad03d3ba3..042959537 100644 --- a/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/Pointer.cs +++ b/src/Generation/Generator/Renderer/Public/InstanceParameterToNativeExpression/Converter/Pointer.cs @@ -9,6 +9,6 @@ public bool Supports(GirModel.Type type) public string GetExpression(GirModel.InstanceParameter instanceParameter) { - return "this.Handle"; + return "this.Handle.DangerousGetHandle()"; } } diff --git a/src/Generation/Generator/Renderer/Public/Interface/InterfaceFramework.cs b/src/Generation/Generator/Renderer/Public/Interface/InterfaceFramework.cs deleted file mode 100644 index 981cbbac4..000000000 --- a/src/Generation/Generator/Renderer/Public/Interface/InterfaceFramework.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Generator.Model; - -namespace Generator.Renderer.Public; - -internal static class InterfaceFramework -{ - public static string Render(GirModel.Interface iface) - { - return $@" -using System; -using GObject; -using System.Runtime.InteropServices; -using System.Runtime.Versioning; - -#nullable enable - -namespace {Namespace.GetPublicName(iface.Namespace)}; - -// AUTOGENERATED FILE - DO NOT MODIFY - -{PlatformSupportAttribute.Render(iface as GirModel.PlatformDependent)} -public partial interface {iface.Name} : GLib.IHandle -{{ -/* - IntPtr GLib.IHandle.Handle - {{ - get - {{ - System.Diagnostics.Debug.Assert( - condition: GetType().IsAssignableTo(typeof(GObject.Object)), - message: $""Interface '{{nameof({iface.Name})}}' can only be implemented on GObject-based classes"" - ); - - return ((GObject.Object)this).Handle; - }} - }} -*/ -}}"; - } -} diff --git a/src/Generation/Generator/Renderer/Public/Interface/InterfaceProperties.cs b/src/Generation/Generator/Renderer/Public/Interface/InterfaceProperties.cs index 6a5222402..ce5dfab02 100644 --- a/src/Generation/Generator/Renderer/Public/Interface/InterfaceProperties.cs +++ b/src/Generation/Generator/Renderer/Public/Interface/InterfaceProperties.cs @@ -12,14 +12,19 @@ public static string Render(GirModel.Interface @interface) return $@" using System; using GObject; +using GObject.Internal; using System.Runtime.InteropServices; + #nullable enable + namespace {Namespace.GetPublicName(@interface.Namespace)} {{ // AUTOGENERATED FILE - DO NOT MODIFY public partial interface {@interface.Name} {{ + ObjectHandle Handle {{ get; }} + {@interface.Properties .Where(Property.IsEnabled) .Select(x => Render(@interface, x)) diff --git a/src/Generation/Generator/Renderer/Public/InterfaceImplementation/InterfaceImplementationFramework.cs b/src/Generation/Generator/Renderer/Public/InterfaceImplementation/InterfaceImplementationFramework.cs index ca5f45776..33dadbbd3 100644 --- a/src/Generation/Generator/Renderer/Public/InterfaceImplementation/InterfaceImplementationFramework.cs +++ b/src/Generation/Generator/Renderer/Public/InterfaceImplementation/InterfaceImplementationFramework.cs @@ -19,11 +19,16 @@ namespace {Namespace.GetPublicName(@interface.Namespace)}; // AUTOGENERATED FILE - DO NOT MODIFY {PlatformSupportAttribute.Render(@interface as GirModel.PlatformDependent)} -public sealed partial class {Interface.GetImplementationName(@interface)} : GObject.Object, {@interface.Name} +public sealed partial class {Interface.GetImplementationName(@interface)} : GObject.Object, {@interface.Name}, GObject.InstanceFactory {{ - public {Interface.GetImplementationName(@interface)}(IntPtr handle, bool ownedRef) : base(handle, ownedRef) + public {Interface.GetImplementationName(@interface)}(GObject.Internal.ObjectHandle handle) : base(handle) {{ }} + + static object GObject.InstanceFactory.Create(IntPtr handle, bool ownsHandle) + {{ + return new {Interface.GetImplementationName(@interface)}(new GObject.Internal.ObjectHandle(handle, ownsHandle)); + }} }}"; } } diff --git a/src/Generation/Generator/Renderer/Public/InterfaceImplementation/InterfaceImplementationProperties.cs b/src/Generation/Generator/Renderer/Public/InterfaceImplementation/InterfaceImplementationProperties.cs index 80dff3caa..7362b4cc0 100644 --- a/src/Generation/Generator/Renderer/Public/InterfaceImplementation/InterfaceImplementationProperties.cs +++ b/src/Generation/Generator/Renderer/Public/InterfaceImplementation/InterfaceImplementationProperties.cs @@ -76,14 +76,14 @@ private static string RenderAccessor(GirModel.ComplexType complexType, GirModel. private static string GetGetter(GirModel.ComplexType complexType, GirModel.Property property) { return Property.SupportsAccessorGetMethod(property, out var getter) - ? $"{Namespace.GetInternalName(complexType.Namespace)}.{complexType.Name}.{Method.GetInternalName(getter)}(Handle)" + ? $"{Namespace.GetInternalName(complexType.Namespace)}.{complexType.Name}.{Method.GetInternalName(getter)}(Handle.DangerousGetHandle())" : $"{ComplexType.GetFullyQualified(complexType)}.{Property.GetDescriptorName(property)}.Get(this)"; } private static string GetSetter(GirModel.ComplexType complexType, GirModel.Property property) { return Property.SupportsAccessorSetMethod(property, out var setter) - ? $"{Namespace.GetInternalName(complexType.Namespace)}.{complexType.Name}.{Method.GetInternalName(setter)}(Handle, value)" + ? $"{Namespace.GetInternalName(complexType.Namespace)}.{complexType.Name}.{Method.GetInternalName(setter)}(Handle.DangerousGetHandle(), value)" : $"{ComplexType.GetFullyQualified(complexType)}.{Property.GetDescriptorName(property)}.Set(this, value)"; } } diff --git a/src/Generation/Generator/Renderer/Public/OpaqueTypedRecord.cs b/src/Generation/Generator/Renderer/Public/OpaqueTypedRecord.cs index ffd186001..a990ee192 100644 --- a/src/Generation/Generator/Renderer/Public/OpaqueTypedRecord.cs +++ b/src/Generation/Generator/Renderer/Public/OpaqueTypedRecord.cs @@ -30,7 +30,7 @@ namespace {Namespace.GetPublicName(record.Namespace)}; // AUTOGENERATED FILE - DO NOT MODIFY {PlatformSupportAttribute.Render(record as GirModel.PlatformDependent)} -public sealed partial class {name} : GLib.BoxedRecord, IEquatable<{name}>, IDisposable +public sealed partial class {name} : GLib.BoxedRecord, GObject.GTypeProvider, GObject.InstanceFactory, IEquatable<{name}>, IDisposable {{ public {internalHandleName} Handle {{ get; }} @@ -38,23 +38,25 @@ public sealed partial class {name} : GLib.BoxedRecord, IEquatable<{name}>, IDisp {{ Handle = handle; Handle.SetMemoryPressure(); - Initialize(); }} - //TODO: This is a workaround constructor as long as we are - //not having https://github.com/gircore/gir.core/issues/397 - private {name}(IntPtr ptr, bool ownsHandle) : this(ownsHandle - ? new {Model.OpaqueTypedRecord.GetFullyQuallifiedOwnedHandle(record)}(ptr) - : new {Model.OpaqueTypedRecord.GetFullyQuallifiedUnownedHandle(record)}(ptr).OwnedCopy()){{ }} + static object GObject.InstanceFactory.Create(IntPtr handle, bool ownsHandle) + {{ + var safeHandle = ownsHandle + ? new {Record.GetFullyQualifiedInternalOwnedHandle(record)}(handle) + : {Record.GetFullyQualifiedInternalOwnedHandle(record)}.FromUnowned(handle); - // Implement this to perform additional steps in the constructor - partial void Initialize(); + return new {name}(safeHandle); + }} {record.Constructors .Select(ConstructorRenderer.Render) .Join(Environment.NewLine)} - {FunctionRenderer.Render(record.TypeFunction)} + public static GObject.Type GetGType() + {{ + return {RenderGetGType(record.TypeFunction!)}; + }} {record.Functions .Select(FunctionRenderer.Render) @@ -100,4 +102,9 @@ public void Dispose() }} }}"; } + + private static string RenderGetGType(GirModel.Function function) + { + return $"{Namespace.GetInternalName(function.Namespace)}.{function.Parent!.Name}.{Function.GetName(function)}()"; + } } diff --git a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/Class.cs b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/Class.cs index 04dc12a0b..2c74bf846 100644 --- a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/Class.cs +++ b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/Class.cs @@ -10,12 +10,22 @@ public bool Supports(GirModel.AnyType type) => type.Is(); public void Initialize(ParameterToNativeData parameter, IEnumerable _) + { + var cls = (GirModel.Class) parameter.Parameter.AnyTypeOrVarArgs.AsT0.AsT0; + + if (cls.Fundamental) + Fundamental(parameter); + else + Default(parameter); + } + + private static void Fundamental(ParameterToNativeData parameter) { if (parameter.Parameter.Direction != GirModel.Direction.In) - throw new NotImplementedException($"{parameter.Parameter.AnyTypeOrVarArgs}: class parameter with direction != in not yet supported"); + throw new NotImplementedException($"{parameter.Parameter.AnyTypeOrVarArgs}: fundamental class parameter with direction != in not yet supported"); if (!parameter.Parameter.IsPointer) - throw new NotImplementedException($"{parameter.Parameter.AnyTypeOrVarArgs}: class parameter which is no pointer can not be converted to native"); + throw new NotImplementedException($"{parameter.Parameter.AnyTypeOrVarArgs}: fundamental class parameter which is no pointer can not be converted to native"); var parameterName = Model.Parameter.GetName(parameter.Parameter); var callParameter = parameter.Parameter.Nullable @@ -37,4 +47,33 @@ public void Initialize(ParameterToNativeData parameter, IEnumerable parameterName); parameter.SetCallName(() => callParameter); } + + private static void Default(ParameterToNativeData parameter) + { + if (parameter.Parameter.Direction != GirModel.Direction.In) + throw new NotImplementedException($"{parameter.Parameter.AnyTypeOrVarArgs}: class parameter with direction != in not yet supported"); + + if (!parameter.Parameter.IsPointer) + throw new NotImplementedException($"{parameter.Parameter.AnyTypeOrVarArgs}: class parameter which is no pointer can not be converted to native"); + + var parameterName = Model.Parameter.GetName(parameter.Parameter); + var callParameter = parameter.Parameter.Nullable + ? parameterName + "?.Handle.DangerousGetHandle() ?? IntPtr.Zero" + : parameterName + ".Handle.DangerousGetHandle()"; + + // If there is an ownership transfer, the called function will not add + // a ref but will hold onto the object and later remove a ref. + // However, the original owned ref still exists (e.g. the managed object's handle) + // so we need to add an extra ref to account for the remaining owner. + if (Transfer.IsOwnedRef(parameter.Parameter.Transfer)) + { + var addRefExpression = parameter.Parameter.Nullable + ? $"if({parameterName}?.Handle is not null) GObject.Internal.Object.Ref({parameterName}.Handle.DangerousGetHandle());" + : $"GObject.Internal.Object.Ref({parameterName}.Handle.DangerousGetHandle());"; + parameter.SetExpression(() => addRefExpression); + } + + parameter.SetSignatureName(() => parameterName); + parameter.SetCallName(() => callParameter); + } } diff --git a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/ClassArray.cs b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/ClassArray.cs index a5755b51d..24f302bb1 100644 --- a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/ClassArray.cs +++ b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/ClassArray.cs @@ -21,6 +21,6 @@ public void Initialize(ParameterToNativeData parameter, IEnumerable parameterName); parameter.SetCallName(() => nativeVariableName); - parameter.SetExpression(() => $"var {nativeVariableName} = {parameterName}.Select(cls => cls.Handle).ToArray();"); + parameter.SetExpression(() => $"var {nativeVariableName} = {parameterName}.Select(cls => cls.Handle.DangerousGetHandle()).ToArray();"); } } diff --git a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/Interface.cs b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/Interface.cs index e3bfc6347..00f68c932 100644 --- a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/Interface.cs +++ b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/Interface.cs @@ -16,8 +16,8 @@ public void Initialize(ParameterToNativeData parameter, IEnumerable parameterName); parameter.SetCallName(() => callParameter); @@ -29,8 +29,8 @@ public void Initialize(ParameterToNativeData parameter, IEnumerable addRefExpression); } } diff --git a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/InterfaceArray.cs b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/InterfaceArray.cs index 955cfef36..fb746f2f4 100644 --- a/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/InterfaceArray.cs +++ b/src/Generation/Generator/Renderer/Public/ParameterToNativeExpression/Converter/InterfaceArray.cs @@ -15,6 +15,6 @@ public void Initialize(ParameterToNativeData parameter, IEnumerable parameterName); parameter.SetCallName(() => nativevariableName); - parameter.SetExpression(() => $"var {nativevariableName} = {parameterName}.Select(iface => (iface as GObject.Object).Handle).ToArray();"); + parameter.SetExpression(() => $"var {nativevariableName} = {parameterName}.Select(iface => (iface as GObject.Object).Handle.DangerousGetHandle()).ToArray();"); } } diff --git a/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/Class.cs b/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/Class.cs index b793509df..cfbee21f0 100644 --- a/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/Class.cs +++ b/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/Class.cs @@ -36,8 +36,9 @@ private static string Fundamental(GirModel.Class cls, GirModel.ReturnType return private static string Standard(GirModel.Class cls, GirModel.ReturnType returnType, string fromVariableName) { + var type = ComplexType.GetFullyQualified(cls); return returnType.Nullable - ? $"GObject.Internal.ObjectWrapper.WrapNullableHandle<{ComplexType.GetFullyQualified(cls)}>({fromVariableName}, {Transfer.IsOwnedRef(returnType.Transfer).ToString().ToLower()})" - : $"GObject.Internal.ObjectWrapper.WrapHandle<{ComplexType.GetFullyQualified(cls)}>({fromVariableName}, {Transfer.IsOwnedRef(returnType.Transfer).ToString().ToLower()})"; + ? $"({type}?) GObject.Internal.InstanceWrapper.WrapNullableHandle<{type}>({fromVariableName}, {Transfer.IsOwnedRef(returnType.Transfer).ToString().ToLower()})" + : $"({type}) GObject.Internal.InstanceWrapper.WrapHandle<{type}>({fromVariableName}, {Transfer.IsOwnedRef(returnType.Transfer).ToString().ToLower()})"; } } diff --git a/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/Interface.cs b/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/Interface.cs index c02863c33..29856cab8 100644 --- a/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/Interface.cs +++ b/src/Generation/Generator/Renderer/Public/ReturnTypeToManagedExpression/Converter/Interface.cs @@ -21,8 +21,8 @@ public void Initialize(ReturnTypeToManagedData data, IEnumerable({fromVariableName}, {Transfer.IsOwnedRef(returnType.Transfer).ToString().ToLower()})" - : $"GObject.Internal.ObjectWrapper.WrapInterfaceHandle<{Model.Interface.GetFullyQualifiedImplementationName(@interface)}>({fromVariableName}, {Transfer.IsOwnedRef(returnType.Transfer).ToString().ToLower()})"; + ? $"({Model.Type.GetPublicNameFullyQuallified(@interface)}?) GObject.Internal.InstanceWrapper.WrapNullableHandle<{Model.Interface.GetFullyQualifiedImplementationName(@interface)}>({fromVariableName}, {Transfer.IsOwnedRef(returnType.Transfer).ToString().ToLower()})" + : $"({Model.Type.GetPublicNameFullyQuallified(@interface)}) GObject.Internal.InstanceWrapper.WrapHandle<{Model.Interface.GetFullyQualifiedImplementationName(@interface)}>({fromVariableName}, {Transfer.IsOwnedRef(returnType.Transfer).ToString().ToLower()})"; }); } } diff --git a/src/Generation/Generator/Renderer/Public/TypedRecord.cs b/src/Generation/Generator/Renderer/Public/TypedRecord.cs index ae8a65f34..c6f089f62 100644 --- a/src/Generation/Generator/Renderer/Public/TypedRecord.cs +++ b/src/Generation/Generator/Renderer/Public/TypedRecord.cs @@ -31,34 +31,36 @@ namespace {Namespace.GetPublicName(record.Namespace)}; // AUTOGENERATED FILE - DO NOT MODIFY {PlatformSupportAttribute.Render(record as GirModel.PlatformDependent)} -public sealed partial class {name} : GLib.BoxedRecord, IEquatable<{name}>, IDisposable +public sealed partial class {name} : GLib.BoxedRecord, GObject.GTypeProvider, GObject.InstanceFactory, IEquatable<{name}>, IDisposable {{ public {internalHandleName} Handle {{ get; }} public {name}({internalHandleName} handle) {{ Handle = handle; - Initialize(); }} public {name}() : this({Model.TypedRecord.GetFullyQuallifiedManagedHandle(record)}.Create()) {{ }} - //TODO: This is a workaround constructor as long as we are - //not having https://github.com/gircore/gir.core/issues/397 - private {name}(IntPtr ptr, bool ownsHandle) : this(ownsHandle - ? new {Model.OpaqueTypedRecord.GetFullyQuallifiedOwnedHandle(record)}(ptr) - : new {Model.OpaqueTypedRecord.GetFullyQuallifiedUnownedHandle(record)}(ptr).OwnedCopy()){{ }} + static object GObject.InstanceFactory.Create(IntPtr handle, bool ownsHandle) + {{ + var safeHandle = ownsHandle + ? new {Record.GetFullyQualifiedInternalOwnedHandle(record)}(handle) + : {Record.GetFullyQualifiedInternalOwnedHandle(record)}.FromUnowned(handle); - // Implement this to perform additional steps in the constructor - partial void Initialize(); + return new {name}(safeHandle); + }} {record.Constructors .Select(ConstructorRenderer.Render) .Join(Environment.NewLine)} - {FunctionRenderer.Render(record.TypeFunction)} + public static GObject.Type GetGType() + {{ + return {RenderGetGType(record.TypeFunction!)}; + }} {record.Fields .Select(f => RenderField(record, f)) @@ -109,6 +111,11 @@ public void Dispose() }}"; } + private static string RenderGetGType(GirModel.Function function) + { + return $"{Namespace.GetInternalName(function.Namespace)}.{function.Parent!.Name}.{Function.GetName(function)}()"; + } + private static string RenderField(GirModel.Record record, GirModel.Field field) { try diff --git a/src/GirCore.Libs.slnf b/src/GirCore.Libs.slnf index f91215e6d..0d321dbc0 100644 --- a/src/GirCore.Libs.slnf +++ b/src/GirCore.Libs.slnf @@ -32,7 +32,6 @@ "Libs\\WebKitWebProcessExtension-6.0\\WebKitWebProcessExtension-6.0.csproj", "Libs\\JavaScriptCore-6.0\\JavaScriptCore-6.0.csproj", "Samples\\Adw-1\\Window\\Window.csproj", - "Samples\\GdkPixbuf-2.0\\TestLoading\\TestLoading.csproj", "Samples\\GdkPixbuf-2.0\\TestMemoryLeaks\\TestMemoryLeaks.csproj", "Samples\\Gio-2.0\\DBus\\DBus.csproj", "Samples\\Gst-1.0\\VideoPlayback\\VideoPlayback.csproj", diff --git a/src/GirCore.sln b/src/GirCore.sln index f7756e68a..111e5c639 100644 --- a/src/GirCore.sln +++ b/src/GirCore.sln @@ -39,11 +39,11 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GstBase-1.0", "Libs\GstBase-1.0\GstBase-1.0.csproj", "{8678914B-C262-4EFB-BCC0-96A15D969C2B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{8BC11A63-D52B-40CB-9DDD-CD7C6DC21059}" - ProjectSection(SolutionItems) = preProject - Tests\Directory.Build.props = Tests\Directory.Build.props - EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libs", "Libs", "{46D66262-FC61-43B9-8E76-A361FA3D6C81}" + ProjectSection(SolutionItems) = preProject + Tests\Libs\Directory.Build.props = Tests\Libs\Directory.Build.props + EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GObject-2.0.Tests", "Tests\Libs\GObject-2.0.Tests\GObject-2.0.Tests.csproj", "{53101A81-CB4A-4589-AEB1-0E229D17AE7A}" EndProject @@ -55,8 +55,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GdkPixbuf-2.0", "GdkPixbuf- EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestMemoryLeaks", "Samples\GdkPixbuf-2.0\TestMemoryLeaks\TestMemoryLeaks.csproj", "{46E769E2-FEC7-43EA-99B8-E7A7294D68B2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestLoading", "Samples\GdkPixbuf-2.0\TestLoading\TestLoading.csproj", "{2BB1527F-D7A1-44BA-A297-4E69A3A4411C}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gtk-4.0.Tests", "Tests\Libs\Gtk-4.0.Tests\Gtk-4.0.Tests.csproj", "{F86D983A-9881-4BE7-AF92-FA0CE41FB319}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Generation", "Generation", "{7A05C10C-8797-4D29-A97A-F399316BE893}" @@ -108,6 +106,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Generation", "Generation", "{5D5D80C1-4D21-4619-8B59-7B7750016E9D}" + ProjectSection(SolutionItems) = preProject + Tests\Generation\Directory.Build.props = Tests\Generation\Directory.Build.props + EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GirLoader.Tests", "Tests\Generation\GirLoader.Tests\GirLoader.Tests.csproj", "{B296273E-1932-4B43-88E5-1F3E9D9D773A}" EndProject @@ -476,18 +477,6 @@ Global {46E769E2-FEC7-43EA-99B8-E7A7294D68B2}.Release|x64.Build.0 = Release|Any CPU {46E769E2-FEC7-43EA-99B8-E7A7294D68B2}.Release|x86.ActiveCfg = Release|Any CPU {46E769E2-FEC7-43EA-99B8-E7A7294D68B2}.Release|x86.Build.0 = Release|Any CPU - {2BB1527F-D7A1-44BA-A297-4E69A3A4411C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2BB1527F-D7A1-44BA-A297-4E69A3A4411C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2BB1527F-D7A1-44BA-A297-4E69A3A4411C}.Debug|x64.ActiveCfg = Debug|Any CPU - {2BB1527F-D7A1-44BA-A297-4E69A3A4411C}.Debug|x64.Build.0 = Debug|Any CPU - {2BB1527F-D7A1-44BA-A297-4E69A3A4411C}.Debug|x86.ActiveCfg = Debug|Any CPU - {2BB1527F-D7A1-44BA-A297-4E69A3A4411C}.Debug|x86.Build.0 = Debug|Any CPU - {2BB1527F-D7A1-44BA-A297-4E69A3A4411C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2BB1527F-D7A1-44BA-A297-4E69A3A4411C}.Release|Any CPU.Build.0 = Release|Any CPU - {2BB1527F-D7A1-44BA-A297-4E69A3A4411C}.Release|x64.ActiveCfg = Release|Any CPU - {2BB1527F-D7A1-44BA-A297-4E69A3A4411C}.Release|x64.Build.0 = Release|Any CPU - {2BB1527F-D7A1-44BA-A297-4E69A3A4411C}.Release|x86.ActiveCfg = Release|Any CPU - {2BB1527F-D7A1-44BA-A297-4E69A3A4411C}.Release|x86.Build.0 = Release|Any CPU {F86D983A-9881-4BE7-AF92-FA0CE41FB319}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F86D983A-9881-4BE7-AF92-FA0CE41FB319}.Debug|Any CPU.Build.0 = Debug|Any CPU {F86D983A-9881-4BE7-AF92-FA0CE41FB319}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -939,7 +928,6 @@ Global {76DD0496-67BC-4B86-BBE1-5648CAF0C719} = {46D66262-FC61-43B9-8E76-A361FA3D6C81} {7A71B07F-B28B-4DDA-B1EA-565194056951} = {1F2E4087-585C-4B48-8E3D-700D949A15DB} {46E769E2-FEC7-43EA-99B8-E7A7294D68B2} = {7A71B07F-B28B-4DDA-B1EA-565194056951} - {2BB1527F-D7A1-44BA-A297-4E69A3A4411C} = {7A71B07F-B28B-4DDA-B1EA-565194056951} {F86D983A-9881-4BE7-AF92-FA0CE41FB319} = {46D66262-FC61-43B9-8E76-A361FA3D6C81} {1EA4392E-960D-4327-9426-4C6220A7B60D} = {7A05C10C-8797-4D29-A97A-F399316BE893} {0D9C5C7E-F81B-4E0E-B203-22D558E6D7F1} = {B670D679-3B2C-43E8-9F87-5E4E17628011} diff --git a/src/Libs/Adw-1/Public/Module.cs b/src/Libs/Adw-1/Public/Module.cs index 214bd4545..862e193e8 100644 --- a/src/Libs/Adw-1/Public/Module.cs +++ b/src/Libs/Adw-1/Public/Module.cs @@ -32,13 +32,16 @@ public static void Initialize() if (IsInitialized) return; + // Set immediately as initialized as static constructors like from Gio.Application + // which get called during "TypeRegistration.RegisterTypes" will call this method again + // resulting in a double execution. A second try would probably make no difference. + IsInitialized = true; + Gio.Module.Initialize(); Gtk.Module.Initialize(); Internal.ImportResolver.RegisterAsDllImportResolver(); Internal.TypeRegistration.RegisterTypes(); Internal.Functions.Init(); - - IsInitialized = true; } } diff --git a/src/Libs/GObject-2.0/Public/GTypeProvider.cs b/src/Libs/GLib-2.0/GObject/Public/GTypeProvider.cs similarity index 76% rename from src/Libs/GObject-2.0/Public/GTypeProvider.cs rename to src/Libs/GLib-2.0/GObject/Public/GTypeProvider.cs index d7e0a5d99..b1f92a56e 100644 --- a/src/Libs/GObject-2.0/Public/GTypeProvider.cs +++ b/src/Libs/GLib-2.0/GObject/Public/GTypeProvider.cs @@ -2,7 +2,5 @@ public interface GTypeProvider { -#if NET7_0_OR_GREATER static abstract Type GetGType(); -#endif } diff --git a/src/Libs/GLib-2.0/GObject/Public/InstanceFactory.cs b/src/Libs/GLib-2.0/GObject/Public/InstanceFactory.cs new file mode 100644 index 000000000..d815d74de --- /dev/null +++ b/src/Libs/GLib-2.0/GObject/Public/InstanceFactory.cs @@ -0,0 +1,8 @@ +using System; + +namespace GObject; + +public interface InstanceFactory +{ + static abstract object Create(IntPtr handle, bool ownsHandle); +} diff --git a/src/Libs/GLib-2.0/Public/IHandle.cs b/src/Libs/GLib-2.0/Public/IHandle.cs deleted file mode 100644 index 86ce1145d..000000000 --- a/src/Libs/GLib-2.0/Public/IHandle.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace GLib; - -public interface IHandle -{ - IntPtr Handle { get; } -} diff --git a/src/Libs/GObject-2.0/Internal/BoxedWrapper.cs b/src/Libs/GObject-2.0/Internal/BoxedWrapper.cs index 373efac44..531fec212 100644 --- a/src/Libs/GObject-2.0/Internal/BoxedWrapper.cs +++ b/src/Libs/GObject-2.0/Internal/BoxedWrapper.cs @@ -1,6 +1,4 @@ using System; -using System.Linq; -using System.Reflection; namespace GObject.Internal; @@ -8,34 +6,13 @@ public class BoxedWrapper { public static object WrapHandle(IntPtr handle, bool ownsHandle, Type gtype) { - System.Type trueType = TypeDictionary.GetSystemType(gtype); - if (handle == IntPtr.Zero) - throw new NullReferenceException($"Failed to wrap handle as type <{trueType}>. Null handle passed to WrapHandle."); - - // Get constructor for the true type - var ctr = GetBoxedConstructor(trueType); - - if (ctr is null) - throw new Exception($"Type {trueType} does not define an IntPtr constructor. This could mean improperly defined bindings"); - - var result = ctr.Invoke(new object[] { handle, ownsHandle }); + throw new NullReferenceException("Failed to wrap boxed handle as a NULL handle was given."); - if (result == null) - throw new Exception($"Type {trueType}'s factory method returned a null object. This could mean improperly defined bindings"); + //Using GObject.Object as a fallback type is not strictly correct as this handler is used for boxed + //records. As boxed records are known through the type system the fallback is never actually used. + var createInstance = DynamicInstanceFactory.GetInstanceFactory(gtype); - return result; - } - - private static ConstructorInfo? GetBoxedConstructor(System.Type type) - { - // Create using 'IntPtr, ownsHandle' constructor - ConstructorInfo? ctor = type.GetConstructor( - System.Reflection.BindingFlags.NonPublic - | System.Reflection.BindingFlags.Public - | System.Reflection.BindingFlags.Instance, - null, new[] { typeof(IntPtr), typeof(bool) }, null - ); - return ctor; + return createInstance(handle, ownsHandle); } } diff --git a/src/Libs/GObject-2.0/Internal/CreateInstance.cs b/src/Libs/GObject-2.0/Internal/CreateInstance.cs new file mode 100644 index 000000000..fd8ec3df4 --- /dev/null +++ b/src/Libs/GObject-2.0/Internal/CreateInstance.cs @@ -0,0 +1,5 @@ +using System; + +namespace GObject.Internal; + +public delegate object CreateInstance(IntPtr handle, bool ownsHandle); diff --git a/src/Libs/GObject-2.0/Internal/DynamicInstanceFactory.cs b/src/Libs/GObject-2.0/Internal/DynamicInstanceFactory.cs new file mode 100644 index 000000000..0c84332ea --- /dev/null +++ b/src/Libs/GObject-2.0/Internal/DynamicInstanceFactory.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace GObject.Internal; + +public static class DynamicInstanceFactory +{ + private static readonly Dictionary InstanceFactories = new(); + + public static void Register(Type type, CreateInstance handleWrapper) + { + InstanceFactories.Add(type, handleWrapper); + } + + internal static object Create(IntPtr handle, bool ownsHandle) where TFallback : InstanceFactory, GTypeProvider + { + var type = GetType(handle); + var createInstance = GetInstanceFactory(type); + return createInstance(handle, ownsHandle); + } + + internal static CreateInstance GetInstanceFactory(Type gtype) where TFallback : InstanceFactory, GTypeProvider + { + if (InstanceFactories.TryGetValue(gtype, out CreateInstance? factory)) + return factory; + + var fallbackType = TFallback.GetGType(); + + // If the gtype is not found this could mean it is some anonymous subclass + // which is not public. So we look for the parent type, because this one could be known. + // If the parent is fundamental (e.g. GObject.Object) this is too unspecific to create. + var parent = GObject.Functions.TypeParent(gtype); + if (!Functions.IsFundamental(parent) && Functions.TypeIsA(parent, fallbackType)) + if (InstanceFactories.TryGetValue(parent, out factory)) + return factory; + + // If the gtype is not found this could mean it implements some known interface + foreach (var iface in GObject.Functions.TypeInterfaces(gtype)) + if (Functions.TypeIsA(iface, fallbackType)) + if (InstanceFactories.TryGetValue(iface, out factory)) + return factory; + + return TFallback.Create; + } + + private static unsafe Type GetType(IntPtr handle) + { + var gclass = Unsafe.AsRef((void*) handle).GClass; + var gtype = Unsafe.AsRef((void*) gclass).GType; + + if (gtype == 0) + throw new Exception("Could not retrieve type from class struct - is the struct valid?"); + + return new Type(gtype); + } +} diff --git a/src/Libs/GObject-2.0/Internal/Functions.cs b/src/Libs/GObject-2.0/Internal/Functions.cs index 2a027e4a3..57e929a21 100644 --- a/src/Libs/GObject-2.0/Internal/Functions.cs +++ b/src/Libs/GObject-2.0/Internal/Functions.cs @@ -14,9 +14,9 @@ public partial class Functions /// Returns whether the given type is a fundamental type. /// /// True if the type is fundamental otherwise false. - public static bool IsFundamental(nuint type) + public static bool IsFundamental(Type type) { //255 << 2 corresponds to G_TYPE_FUNDAMENTAL_MAX - return type <= (255 << 2); + return type.Value <= (255 << 2); } } diff --git a/src/Libs/GObject-2.0/Internal/GTypeProviderHelper.cs b/src/Libs/GObject-2.0/Internal/GTypeProviderHelper.cs deleted file mode 100644 index c118e82aa..000000000 --- a/src/Libs/GObject-2.0/Internal/GTypeProviderHelper.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace GObject.Internal; - -#if NET6_0 - -//TODO: Remove this class once support for dotnet 6 is dropped -public static class GTypeProviderHelper -{ - public static Type GetGType() where T : GObject.Object, GTypeProvider - { - var getGTypeMethod = typeof(T).GetMethod(nameof(GObject.Object.GetGType)); - - if (getGTypeMethod is null) - throw new Exception($"Method {nameof(GObject.Object.GetGType)} not found on {typeof(T).Name}"); - - return (Type) (getGTypeMethod.Invoke(null, null) ?? throw new Exception($"Method {nameof(GObject.Object.GetGType)} on {typeof(T).Name} did not return a result")); - } -} -#endif diff --git a/src/Libs/GObject-2.0/Internal/InstanceCache.cs b/src/Libs/GObject-2.0/Internal/InstanceCache.cs new file mode 100644 index 000000000..46bf69408 --- /dev/null +++ b/src/Libs/GObject-2.0/Internal/InstanceCache.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +namespace GObject.Internal; + +internal static class InstanceCache +{ + private static readonly object Lock = new(); + private static readonly Dictionary Cache = new(); + internal static int ObjectCount + { + get + { + lock (Lock) + { + return Cache.Count; + } + } + } + + public static bool TryGetObject(IntPtr handle, [NotNullWhen(true)] out GObject.Object? obj) + { + lock (Lock) + { + if (Cache.TryGetValue(handle, out ToggleRef? toggleRef)) + { + if (toggleRef.Object is not null) + { + obj = toggleRef.Object; + return true; + } + } + } + + obj = null; + return false; + } + + public static unsafe void Add(IntPtr handle, GObject.Object obj) + { + lock (Cache) + { + Cache[handle] = new ToggleRef(obj); + ToggleRegistration.AddToggleRef(handle, &ToggleNotify); + Object.Unref(handle); + } + + Debug.WriteLine($"Handle {handle}: Added object of type '{obj.GetType()}' to {nameof(InstanceCache)}"); + } + + public static unsafe void Remove(IntPtr handle) + { + lock (Cache) + { + if (Cache.Remove(handle)) + ToggleRegistration.RemoveToggleRef(handle, &ToggleNotify); + } + + Debug.WriteLine($"Handle {handle}: Removed object from {nameof(InstanceCache)}."); + } + + [UnmanagedCallersOnly] + private static void ToggleNotify(IntPtr data, IntPtr @object, int isLastRef) + { + lock (Lock) + { + if (Cache.TryGetValue(@object, out var toggleRef)) + toggleRef.ToggleReference(isLastRef != 0); + else + Debug.WriteLine($"Handle {@object}: Could not toggle to {isLastRef} as there is no toggle reference."); + } + } +} diff --git a/src/Libs/GObject-2.0/Internal/InstanceWrapper.cs b/src/Libs/GObject-2.0/Internal/InstanceWrapper.cs new file mode 100644 index 000000000..6585b3d36 --- /dev/null +++ b/src/Libs/GObject-2.0/Internal/InstanceWrapper.cs @@ -0,0 +1,24 @@ +using System; + +namespace GObject.Internal; + +public static class InstanceWrapper +{ + public static object? WrapNullableHandle(IntPtr handle, bool ownedRef) where TFallback : InstanceFactory, GTypeProvider + { + return handle == IntPtr.Zero + ? null + : WrapHandle(handle, ownedRef); + } + + public static object WrapHandle(IntPtr handle, bool ownedRef) where TFallback : InstanceFactory, GTypeProvider + { + if (handle == IntPtr.Zero) + throw new NullReferenceException("Failed to wrap handle: Null handle passed to WrapHandle."); + + if (InstanceCache.TryGetObject(handle, out var obj)) + return obj; + + return DynamicInstanceFactory.Create(handle, ownedRef); + } +} diff --git a/src/Libs/GObject-2.0/Internal/ObjectHandle.cs b/src/Libs/GObject-2.0/Internal/ObjectHandle.cs index c7b8070d1..55af61604 100644 --- a/src/Libs/GObject-2.0/Internal/ObjectHandle.cs +++ b/src/Libs/GObject-2.0/Internal/ObjectHandle.cs @@ -1,23 +1,72 @@ using System; +using System.Diagnostics; +using System.Linq; using System.Runtime.InteropServices; namespace GObject.Internal; public class ObjectHandle : SafeHandle { - public IntPtr Handle => IsInvalid ? IntPtr.Zero : DangerousGetHandle(); + public override bool IsInvalid => handle == IntPtr.Zero; - public ObjectHandle(IntPtr handle, object obj, bool ownedRef) : base(IntPtr.Zero, true) + public ObjectHandle(IntPtr handle, bool ownsHandle) : base(IntPtr.Zero, true) { - ObjectMapper.Map(handle, obj, ownedRef); SetHandle(handle); + OwnReference(ownsHandle); } - public sealed override bool IsInvalid => handle == IntPtr.Zero; + private void OwnReference(bool ownedRef) + { + if (!ownedRef) + { + // - Unowned GObjects need to be refed to bind them to this instance + // - Unowned InitiallyUnowned floating objects need to be ref_sinked + // - Unowned InitiallyUnowned non-floating objects need to be refed + // As ref_sink behaves like ref in case of non floating instances we use it for all 3 cases + Object.RefSink(handle); + } + else + { + //In case we own the ref because the ownership was fully transfered to us we + //do not need to ref the object at all. + + Debug.Assert(!Internal.Object.IsFloating(handle), $"Handle {handle}: Owned floating references are not possible."); + } + } + + internal void Cache(GObject.Object obj) + { + Debug.Assert(handle == obj.Handle.DangerousGetHandle(), "Must cache the instance of this handle."); + + InstanceCache.Add(handle, obj); + } - protected sealed override bool ReleaseHandle() + protected override bool ReleaseHandle() { - ObjectMapper.Unmap(handle); + RemoveMemoryPressure(); + InstanceCache.Remove(handle); return true; } + + protected internal virtual void AddMemoryPressure() { } + protected virtual void RemoveMemoryPressure() { } + + public static ObjectHandle For(bool owned, ConstructArgument[] constructArguments) where T : GObject.Object, GTypeProvider + { + // We can't check if a reference is floating via "g_object_is_floating" here + // as the function could be "lying" depending on the intent of framework writers. + // E.g. A Gtk.Window created via "g_object_new_with_properties" returns an unowned + // reference which is not marked as floating as the gtk toolkit "owns" it. + // For this reason we just delegate the problem to the caller and require a + // definition whether the ownership of the new object will be transferred to us or not. + + var ptr = Object.NewWithProperties( + objectType: T.GetGType(), + nProperties: (uint) constructArguments.Length, + names: constructArguments.Select(x => x.Name).ToArray(), + values: GObject.Internal.ValueArray2OwnedHandle.Create(constructArguments.Select(x => x.Value).ToArray()) + ); + + return new ObjectHandle(ptr, owned); + } } diff --git a/src/Libs/GObject-2.0/Internal/ObjectMapper.ToggleRef.cs b/src/Libs/GObject-2.0/Internal/ObjectMapper.ToggleRef.cs deleted file mode 100644 index cd54ed862..000000000 --- a/src/Libs/GObject-2.0/Internal/ObjectMapper.ToggleRef.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Diagnostics; - -namespace GObject.Internal; - -public partial class ObjectMapper -{ - private class ToggleRef - { - private object _reference; - private readonly IntPtr _handle; - - public object? Object - { - get - { - if (_reference is not WeakReference weakRef) - return _reference; - - if (weakRef.Target is { } target) - return target; - - return null; - } - } - - /// - /// Initializes a toggle ref. The given object must be already owned by C# as the owned - /// reference is exchanged with a toggling reference meaning the toggle reference is taking control - /// over the reference. - /// This object saves a strong reference to the given object which prevents it from beeing garbage - /// collected. This strong reference is hold as long as there are other than our own toggling ref - /// on the given object. - /// If our toggeling ref is the last ref on the given object the strong reference is changed into a - /// weak reference. This allows the garbage collector to free the C# object which must result in the - /// call of the Dispose method of the ToggleRef. The Dispose mehtod removes the added toggle reference - /// and thus frees the last reference to the C object. - /// - public ToggleRef(IntPtr handle, object obj, bool ownedRef) - { - _reference = obj; - _handle = handle; - - OwnReference(ownedRef); - } - - private void OwnReference(bool ownedRef) - { - if (!ownedRef) - { - // - Unowned GObjects need to be refed to bind them to this instance - // - Unowned InitiallyUnowned floating objects need to be ref_sinked - // - Unowned InitiallyUnowned non-floating objects need to be refed - // As ref_sink behaves like ref in case of non floating instances we use it for all 3 cases - Internal.Object.RefSink(_handle); - } - else - { - //In case we own the ref because the ownership was fully transfered to us we - //do not need to ref the object at all. - - Debug.Assert(!Internal.Object.IsFloating(_handle), $"Handle {_handle}: Owned floating references are not possible."); - } - } - - internal void ToggleReference(bool isLastRef) - { - if (!isLastRef && _reference is WeakReference weakRef) - { - if (weakRef.Target is { } weakObj) - _reference = weakObj; - else - throw new Exception($"Handle {_handle}: Could not toggle reference to strong. It got garbage collected."); - } - else if (isLastRef && _reference is not WeakReference) - { - _reference = new WeakReference(_reference); - } - } - } -} diff --git a/src/Libs/GObject-2.0/Internal/ObjectMapper.ToggleRegistration.cs b/src/Libs/GObject-2.0/Internal/ObjectMapper.ToggleRegistration.cs deleted file mode 100644 index 0cc784e44..000000000 --- a/src/Libs/GObject-2.0/Internal/ObjectMapper.ToggleRegistration.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace GObject.Internal; - -public partial class ObjectMapper -{ - private static unsafe class ToggleRegistration - { - internal static void AddToggleRef(IntPtr handle) - { - AddToggleRef(handle, &ToggleNotify, IntPtr.Zero); - Internal.Object.Unref(handle); - } - - internal static void RemoveToggleRef(IntPtr handle) - { - var sourceFunc = new GLib.Internal.SourceFuncAsyncHandler(() => - { - RemoveToggleRef(handle, &ToggleNotify, IntPtr.Zero); - return false; - }); - GLib.Internal.MainContext.Invoke(GLib.Internal.MainContextUnownedHandle.NullHandle, sourceFunc.NativeCallback, IntPtr.Zero); - } - - [DllImport(ImportResolver.Library, EntryPoint = "g_object_add_toggle_ref")] - private static extern void AddToggleRef(IntPtr @object, delegate* unmanaged toggleNotify, IntPtr data); - - [DllImport(ImportResolver.Library, EntryPoint = "g_object_remove_toggle_ref")] - private static extern void RemoveToggleRef(IntPtr @object, delegate* unmanaged toggleNotify, IntPtr data); - } -} diff --git a/src/Libs/GObject-2.0/Internal/ObjectMapper.cs b/src/Libs/GObject-2.0/Internal/ObjectMapper.cs deleted file mode 100644 index 80bc5c5f4..000000000 --- a/src/Libs/GObject-2.0/Internal/ObjectMapper.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using GLib; - -namespace GObject.Internal; - -public static partial class ObjectMapper -{ - private static readonly object Lock = new(); - private static readonly Dictionary WrapperObjects = new(); - - public static int ObjectCount - { - get - { - lock (Lock) - { - return WrapperObjects.Count; - } - } - } - - public static bool TryGetObject(IntPtr handle, [NotNullWhen(true)] out T? obj) where T : class, IHandle - { - lock (Lock) - { - if (WrapperObjects.TryGetValue(handle, out ToggleRef? weakRef)) - { - if (weakRef.Object is not null) - { - obj = (T) weakRef.Object; - return true; - } - } - } - - obj = null; - return false; - } - - public static void Map(IntPtr handle, object obj, bool ownedRef) - { - lock (Lock) - { - WrapperObjects[handle] = new ToggleRef(handle, obj, ownedRef); - ToggleRegistration.AddToggleRef(handle); - } - - Debug.WriteLine($"Handle {handle}: Mapped object of type '{obj.GetType()}' as owned ref '{ownedRef}'."); - } - - public static void Unmap(IntPtr handle) - { - lock (Lock) - { - if (WrapperObjects.Remove(handle)) - ToggleRegistration.RemoveToggleRef(handle); - } - - Debug.WriteLine($"Handle {handle}: Unmapped object."); - } - - [UnmanagedCallersOnly] - private static void ToggleNotify(IntPtr data, IntPtr @object, int isLastRef) - { - lock (Lock) - { - if (WrapperObjects.TryGetValue(@object, out var toggleRef)) - toggleRef.ToggleReference(isLastRef != 0); - else - Debug.WriteLine($"Handle {@object}: Could not toggle to {isLastRef} as there is no toggle reference."); - } - } -} diff --git a/src/Libs/GObject-2.0/Internal/ObjectWrapper.cs b/src/Libs/GObject-2.0/Internal/ObjectWrapper.cs deleted file mode 100644 index 48640d48b..000000000 --- a/src/Libs/GObject-2.0/Internal/ObjectWrapper.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Diagnostics; -using System.Reflection; -using System.Runtime.CompilerServices; -using GLib; - -namespace GObject.Internal; - -public static class ObjectWrapper -{ - public static T? WrapNullableHandle(IntPtr handle, bool ownedRef) where T : class, IHandle - { - return handle == IntPtr.Zero - ? null - : WrapHandle(handle, ownedRef); - } - - public static T WrapHandle(IntPtr handle, bool ownedRef) where T : class, IHandle - { - Debug.Assert( - condition: typeof(T).IsClass && typeof(T).IsAssignableTo(typeof(GObject.Object)), - message: "Type 'T' must be a GObject-based class" - ); - - if (handle == IntPtr.Zero) - throw new NullReferenceException($"Failed to wrap handle as type <{typeof(T).FullName}>. Null handle passed to WrapHandle."); - - if (ObjectMapper.TryGetObject(handle, out T? obj)) - return obj; - - //In case of classes prefer the type reported by the gobject type system over - //the expected type as often an API returns a less derived class in it's public - //API then the actual one. - Type gtype = GetTypeFromInstance(handle); - - Debug.Assert( - condition: Functions.TypeName(gtype.Value).ConvertToString() == Functions.TypeNameFromInstance(new TypeInstanceUnownedHandle(handle)).ConvertToString(), - message: "GType name of instance and class do not match" - ); - - System.Type trueType = TypeDictionary.GetSystemType(gtype); - ConstructorInfo? ctor = GetObjectConstructor(trueType); - - if (ctor == null) - throw new Exception($"Type {typeof(T).FullName} does not define an IntPtr constructor. This could mean improperly defined bindings"); - - return (T) ctor.Invoke(new object[] { handle, ownedRef }); - } - - public static T? WrapNullableInterfaceHandle(IntPtr handle, bool ownedRef) where T : class, IHandle - { - return handle == IntPtr.Zero - ? null - : WrapInterfaceHandle(handle, ownedRef); - } - - public static T WrapInterfaceHandle(IntPtr handle, bool ownedRef) where T : class, IHandle - { - Debug.Assert( - condition: typeof(T).IsClass && typeof(T).IsAssignableTo(typeof(GObject.Object)), - message: "Type 'T' must be a GObject-based class" - ); - - if (handle == IntPtr.Zero) - throw new NullReferenceException($"Failed to wrap handle as type <{typeof(T).FullName}>. Null handle passed to WrapHandle."); - - if (ObjectMapper.TryGetObject(handle, out T? obj)) - return obj; - - //In case of interfaces prefer the given type over the type reported by the gobject - //type system as the reported type is probably not part of the public API. Otherwise the - //class itself would be returned and not an interface. - ConstructorInfo? ctor = GetObjectConstructor(typeof(T)); - - if (ctor == null) - throw new Exception($"Type {typeof(T).FullName} does not define an IntPtr constructor. This could mean improperly defined bindings"); - - return (T) ctor.Invoke(new object[] { handle, ownedRef }); - } - - private static unsafe Type GetTypeFromInstance(IntPtr handle) - { - var gclass = Unsafe.AsRef((void*) handle).GClass; - var gtype = Unsafe.AsRef((void*) gclass).GType; - - if (gtype == 0) - throw new Exception("Could not retrieve type from class struct - is the struct valid?"); - - return new Type(gtype); - } - - private static ConstructorInfo? GetObjectConstructor(System.Type type) - { - // Create using 'IntPtr' constructor - ConstructorInfo? ctor = type.GetConstructor( - System.Reflection.BindingFlags.NonPublic - | System.Reflection.BindingFlags.Public - | System.Reflection.BindingFlags.Instance, - null, new[] { typeof(IntPtr), typeof(bool) }, null - ); - return ctor; - } -} diff --git a/src/Libs/GObject-2.0/Internal/SubclassRegistrar.cs b/src/Libs/GObject-2.0/Internal/SubclassRegistrar.cs new file mode 100644 index 000000000..1dd86934e --- /dev/null +++ b/src/Libs/GObject-2.0/Internal/SubclassRegistrar.cs @@ -0,0 +1,77 @@ +using System.Diagnostics; + +namespace GObject.Internal; + +/// +/// Registers a custom subclass with the GObject type system. +/// +public static class SubclassRegistrar +{ + public static Type Register() + where TSubclass : InstanceFactory + where TParent : GTypeProvider + { + var newType = RegisterNewGType(); + DynamicInstanceFactory.Register(newType, TSubclass.Create); + + return newType; + } + + private static Type RegisterNewGType() + where TParent : GTypeProvider + { + var parentType = TParent.GetGType(); + var parentTypeInfo = TypeQueryOwnedHandle.Create(); + Functions.TypeQuery(parentType, parentTypeInfo); + + if (parentTypeInfo.GetType() == 0) + throw new TypeRegistrationException("Could not query parent type"); + + Debug.WriteLine($"Registering new type {typeof(TSubclass).FullName} with parent {typeof(TParent).FullName}"); + + // Create TypeInfo + //TODO: Callbacks for "ClassInit" and "InstanceInit" are disabled because if multiple instances + //of the same type are created, the typeInfo object can get garbagec collected in the mean time + //and with it the instances of "DoClassInit" and "DoInstanceInit". If the callback occurs the + //runtime can't do the call anymore and crashes with: + //A callback was made on a garbage collected delegate of type 'GObject-2.0!GObject.Internal.InstanceInitFunc::Invoke' + //Fix this by caching the garbage collected instances somehow + var handle = TypeInfoOwnedHandle.Create(); + handle.SetClassSize((ushort) parentTypeInfo.GetClassSize()); + handle.SetInstanceSize((ushort) parentTypeInfo.GetInstanceSize()); + //handle.SetClassInit(); + //handle.SetInstanceInit(); + + var qualifiedName = QualifyName(typeof(TSubclass)); + var typeid = Functions.TypeRegisterStatic(parentType, + GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(qualifiedName), handle, 0); + + if (typeid == 0) + throw new TypeRegistrationException("Type Registration Failed!"); + + return new Type(typeid); + } + + private static string QualifyName(System.Type type) + => type.ToString() + .Replace(".", string.Empty) + .Replace("+", string.Empty) + .Replace("`", string.Empty) + .Replace("[", "_") + .Replace("]", string.Empty) + .Replace(" ", string.Empty) + .Replace(",", "_"); + + /* TODO: Enable if init functions are supported again + // Default Handler for class initialisation. + private static void DoClassInit(IntPtr gClass, IntPtr classData) + { + Console.WriteLine("Subclass type class initialised!"); + } + // Default Handler for instance initialisation. + private static void DoInstanceInit(IntPtr gClass, IntPtr classData) + { + Console.WriteLine("Subclass instance initialised!"); + } + */ +} diff --git a/src/Libs/GObject-2.0/Internal/ToggleRef.cs b/src/Libs/GObject-2.0/Internal/ToggleRef.cs new file mode 100644 index 000000000..dd445d7ef --- /dev/null +++ b/src/Libs/GObject-2.0/Internal/ToggleRef.cs @@ -0,0 +1,46 @@ +using System; + +namespace GObject.Internal; + +internal class ToggleRef +{ + private object _reference; + + public GObject.Object? Object + { + get + { + if (_reference is WeakReference weakRef) + return (GObject.Object?) weakRef.Target; + + return (GObject.Object) _reference; + } + } + + /// + /// This object saves a strong reference to the given object which prevents it from beeing garbage + /// collected. This strong reference is hold as long as there are other references than the toggling ref + /// on the given object. + /// If the toggeling ref is the last ref on the given object the strong reference is changed into a + /// weak reference. This is signaled via a call to "ToggleReference". + /// + public ToggleRef(GObject.Object obj) + { + _reference = obj; + } + + internal void ToggleReference(bool isLastRef) + { + if (!isLastRef && _reference is WeakReference weakRef) + { + if (weakRef.Target is { } weakObj) + _reference = weakObj; + else + throw new Exception("Could not toggle reference to strong. It got garbage collected."); + } + else if (isLastRef && _reference is not WeakReference) + { + _reference = new WeakReference(_reference); + } + } +} diff --git a/src/Libs/GObject-2.0/Internal/ToggleRegistration.cs b/src/Libs/GObject-2.0/Internal/ToggleRegistration.cs new file mode 100644 index 000000000..f063a5d3a --- /dev/null +++ b/src/Libs/GObject-2.0/Internal/ToggleRegistration.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.InteropServices; + +namespace GObject.Internal; + +internal static unsafe class ToggleRegistration +{ + internal static void AddToggleRef(IntPtr handle, delegate* unmanaged toggleNotify) + { + AddToggleRef(handle, toggleNotify, IntPtr.Zero); + } + + internal static void RemoveToggleRef(IntPtr handle, delegate* unmanaged toggleNotify) + { + var sourceFunc = new GLib.Internal.SourceFuncAsyncHandler(() => + { + RemoveToggleRef(handle, toggleNotify, IntPtr.Zero); + return false; + }); + GLib.Internal.MainContext.Invoke(GLib.Internal.MainContextUnownedHandle.NullHandle, sourceFunc.NativeCallback, IntPtr.Zero); + } + + [DllImport(ImportResolver.Library, EntryPoint = "g_object_add_toggle_ref")] + private static extern void AddToggleRef(IntPtr @object, delegate* unmanaged toggleNotify, IntPtr data); + + [DllImport(ImportResolver.Library, EntryPoint = "g_object_remove_toggle_ref")] + private static extern void RemoveToggleRef(IntPtr @object, delegate* unmanaged toggleNotify, IntPtr data); +} diff --git a/src/Libs/GObject-2.0/Internal/TypeDictionary.cs b/src/Libs/GObject-2.0/Internal/TypeDictionary.cs deleted file mode 100644 index 82088b822..000000000 --- a/src/Libs/GObject-2.0/Internal/TypeDictionary.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; - -namespace GObject.Internal; - -/// -/// This exception is thrown when a is not found in -/// the type dictionary. -/// -public class TypeNotFoundException : Exception -{ - public TypeNotFoundException(System.Type managedType) - : base($"Type {managedType.FullName} not registered in type dictionary") { } -} - - - -/// -/// The global type dictionary which maps between the .NET Type System and -/// the GType dynamic type system. -/// -public static class TypeDictionary -{ - private static readonly Dictionary _systemTypeDict = new(); - private static readonly Dictionary _reverseTypeDict = new(); - - /// - /// Add a new mapping of (System.Type, GObject.Type) to the type dictionary. - /// - /// A managed type that has not already been registered - /// The gtype retrieved from the object's get type method or from registration. - public static void Add(System.Type systemType, Type type) - { - // Check we have not already registered - Debug.Assert( - condition: !_systemTypeDict.ContainsKey(systemType), - message: $"Type {nameof(systemType)} is already registered in the type dictionary." - ); - - _systemTypeDict[systemType] = type; - _reverseTypeDict[type] = systemType; - } - - /// - /// For a given managed GObject-based class, retrieve the corresponding gtype. - /// - /// The type of a class that is equal or derived from - /// The equivalent GType - /// The given type is not registered in the type dictionary. The caller should register it themselves. - internal static Type GetGType(System.Type type) - { - Debug.Assert( - condition: type.IsAssignableTo(typeof(GObject.Object)), - message: $"Parameter {type} is not a GObject or subclass of GObject" - ); - - if (!_systemTypeDict.TryGetValue(type, out Type gType)) - throw new TypeNotFoundException(type); - - return gType; - } - - /// - /// For a given gtype, retrieve the corresponding managed type. - /// - /// A type from the GType type system - /// The equivalent managed type - internal static System.Type GetSystemType(Type gtype) - { - if (_reverseTypeDict.TryGetValue(gtype, out System.Type? sysType)) - return sysType; - - // If gtype is not in the type dictionary, walk up the - // tree until we find a type that is. As all objects are - // descended from GObject, we will eventually find a parent - // type that is registered. - - while (!_reverseTypeDict.TryGetValue(gtype, out sysType)) - { - gtype = new Type(Functions.TypeParent(gtype.Value)); - if (gtype.Value == (nuint) BasicType.Invalid || - gtype.Value == (nuint) BasicType.None) - throw new Exception("Could not retrieve parent type - is the typeid valid?"); - } - - // Store for future lookups - _reverseTypeDict[gtype] = sysType; - - return sysType; - } - - // These may be unneeded - keep for now - internal static bool ContainsGType(Type gtype) - => _reverseTypeDict.ContainsKey(gtype); - - internal static bool ContainsSystemType(System.Type type) - => _systemTypeDict.ContainsKey(type); -} diff --git a/src/Libs/GObject-2.0/Internal/TypeRegistrar.cs b/src/Libs/GObject-2.0/Internal/TypeRegistrar.cs deleted file mode 100644 index 6c71d6e0e..000000000 --- a/src/Libs/GObject-2.0/Internal/TypeRegistrar.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace GObject.Internal; - -/// -/// Thrown when type registration with GType fails -/// -internal class TypeRegistrationException : Exception -{ - public TypeRegistrationException(string message) : base(message) { } -} - -/// -/// A set of utility functions to register new types with the -/// GType dynamic type system. -/// -public static class TypeRegistrar -{ - /// - /// Registers with GType a new child class of 'parentType'. - /// - /// The name of the class - /// The parent class to derive from - /// The newly registered type - /// The type could not be registered - internal static Type RegisterGType(string qualifiedName, Type parentType) - { - var typeQuery = TypeQueryOwnedHandle.Create(); - Functions.TypeQuery(parentType, typeQuery); - - if (typeQuery.GetType() == 0) - throw new TypeRegistrationException("Could not query parent type"); - - Debug.WriteLine($"Registering new type {qualifiedName} with parent {parentType.ToString()}"); - - // Create TypeInfo - //TODO: Callbacks for "ClassInit" and "InstanceInit" are disabled because if multiple instances - //of the same type are created, the typeInfo object can get garbagec collected in the mean time - //and with it the instances of "DoClassInit" and "DoInstanceInit". If the callback occurs the - //runtime can't do the call anymore and crashes with: - //A callback was made on a garbage collected delegate of type 'GObject-2.0!GObject.Internal.InstanceInitFunc::Invoke' - //Fix this by caching the garbage collected instances somehow - var handle = TypeInfoOwnedHandle.Create(); - handle.SetClassSize((ushort) typeQuery.GetClassSize()); - handle.SetInstanceSize((ushort) typeQuery.GetInstanceSize()); - //handle.SetClassInit(); - //handle.SetInstanceInit(); - - var typeid = Functions.TypeRegisterStatic(parentType, GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(qualifiedName), handle, 0); - - if (typeid == 0) - throw new TypeRegistrationException("Type Registration Failed!"); - - return new Type(typeid); - } - - /* TODO: Enable if init functions are supported again - // Default Handler for class initialisation. - private static void DoClassInit(IntPtr gClass, IntPtr classData) - { - Console.WriteLine("Subclass type class initialised!"); - } - - // Default Handler for instance initialisation. - private static void DoInstanceInit(IntPtr gClass, IntPtr classData) - { - Console.WriteLine("Subclass instance initialised!"); - } - */ -} diff --git a/src/Libs/GObject-2.0/Internal/TypeRegistrationException.cs b/src/Libs/GObject-2.0/Internal/TypeRegistrationException.cs new file mode 100644 index 000000000..52180a160 --- /dev/null +++ b/src/Libs/GObject-2.0/Internal/TypeRegistrationException.cs @@ -0,0 +1,11 @@ +using System; + +namespace GObject.Internal; + +/// +/// Thrown when type registration with GType fails +/// +public class TypeRegistrationException : Exception +{ + internal TypeRegistrationException(string message) : base(message) { } +} diff --git a/src/Libs/GObject-2.0/Public/AssemblyExtension.cs b/src/Libs/GObject-2.0/Public/AssemblyExtension.cs index 020d683a6..7a3ad06d2 100644 --- a/src/Libs/GObject-2.0/Public/AssemblyExtension.cs +++ b/src/Libs/GObject-2.0/Public/AssemblyExtension.cs @@ -16,7 +16,7 @@ public static byte[] ReadResourceAsByteArray(this Assembly assembly, string reso var size = (int) stream.Length; var buffer = new byte[size]; - stream.Read(buffer, 0, size); + stream.ReadExactly(buffer, 0, size); stream.Close(); return buffer; diff --git a/src/Libs/GObject-2.0/Public/Closure.cs b/src/Libs/GObject-2.0/Public/Closure.cs index 70a64a03d..1082493df 100644 --- a/src/Libs/GObject-2.0/Public/Closure.cs +++ b/src/Libs/GObject-2.0/Public/Closure.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics; -using System.Linq; using System.Runtime.InteropServices; namespace GObject; diff --git a/src/Libs/GObject-2.0/Public/ConstructArgument.cs b/src/Libs/GObject-2.0/Public/ConstructArgument.cs index 416c2ace6..c8ba98416 100644 --- a/src/Libs/GObject-2.0/Public/ConstructArgument.cs +++ b/src/Libs/GObject-2.0/Public/ConstructArgument.cs @@ -5,23 +5,17 @@ namespace GObject; /// /// Define the value of GProperty which can be used at the construct time. /// -public sealed class ConstructArgument : IDisposable +public sealed class ConstructArgument(string name, Value value) : IDisposable { /// /// The GProperty name to set at the construct time. /// - public string Name { get; } + public string Name { get; } = name; /// /// The value of the property. /// - public Value Value { get; } - - public ConstructArgument(string name, Value value) - { - Name = name; - Value = value; - } + public Value Value { get; } = value; public void Dispose() { diff --git a/src/Libs/GObject-2.0/Public/IObject.cs b/src/Libs/GObject-2.0/Public/IObject.cs deleted file mode 100644 index 1569b7111..000000000 --- a/src/Libs/GObject-2.0/Public/IObject.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; -using System.ComponentModel; - -namespace GObject; - -public interface IObject -{ - -} diff --git a/src/Libs/GObject-2.0/Public/Object.Registration.cs b/src/Libs/GObject-2.0/Public/Object.Registration.cs deleted file mode 100644 index 68c98aa1f..000000000 --- a/src/Libs/GObject-2.0/Public/Object.Registration.cs +++ /dev/null @@ -1,58 +0,0 @@ -using GObject.Internal; - -namespace GObject; - -public partial class Object -{ - private Type GetGTypeOrRegister(System.Type type) - { - if (TypeDictionary.ContainsSystemType(type)) - return TypeDictionary.GetGType(type); - - // We are not in the type dictionary, which means we are - // an unregistered managed subclass type. There are two ways - // to register subclasses: Dynamically (reflection) and - // Statically (by source generation). - - // Static registration happens on application startup in the - // module initialiser if source generator support is present - // at build time (note: not implemented as of 29/04/21) - - // Therefore, we can assume static registration did not go ahead - // and we should resort to the fallback reflection-based registration - // implemented below. We should therefore register ourselves - // and every type we inherit from that has also not been registered. - - FallbackRegistrationStrategy.RegisterSubclassRecursive(type); - - return TypeDictionary.GetGType(type); - } - - private static class FallbackRegistrationStrategy - { - private static string QualifyName(System.Type type) - => type.ToString() - .Replace(".", string.Empty) - .Replace("+", string.Empty) - .Replace("`", string.Empty) - .Replace("[", "_") - .Replace("]", string.Empty) - .Replace(" ", string.Empty) - .Replace(",", "_"); - - public static void RegisterSubclassRecursive(System.Type type) - { - System.Type baseType = type.BaseType!; - if (!TypeDictionary.ContainsSystemType(baseType)) - RegisterSubclassRecursive(baseType); - - // Do actual registration - Type gtype = TypeRegistrar.RegisterGType( - qualifiedName: QualifyName(type), - parentType: TypeDictionary.GetGType(baseType) - ); - - TypeDictionary.Add(type, gtype); - } - } -} diff --git a/src/Libs/GObject-2.0/Public/Object.Signals.cs b/src/Libs/GObject-2.0/Public/Object.Signals.cs index fe7bb11c4..7b90b9298 100644 --- a/src/Libs/GObject-2.0/Public/Object.Signals.cs +++ b/src/Libs/GObject-2.0/Public/Object.Signals.cs @@ -11,7 +11,7 @@ public partial class Object internal void SignalConnectClosure(SignalDefinition signalDefinition, Delegate callback, Closure closure, bool after, string? detail) { var detailQuark = GLib.Functions.QuarkFromString(detail); - var handlerId = Internal.Functions.SignalConnectClosureById(Handle, signalDefinition.Id, detailQuark, closure.Handle, after); + var handlerId = Internal.Functions.SignalConnectClosureById(Handle.DangerousGetHandle(), signalDefinition.Id, detailQuark, closure.Handle, after); if (handlerId.Value == 0) throw new Exception($"Could not connect to event {signalDefinition.ManagedName}"); @@ -24,7 +24,7 @@ internal void Disconnect(SignalDefinition signalDefinition, Delegate callback) if (!_signalStore.TryGetValue((signalDefinition, callback), out var tuple)) return; - Internal.Functions.SignalHandlerDisconnect(Handle, tuple.Item1); + Internal.Functions.SignalHandlerDisconnect(Handle.DangerousGetHandle(), tuple.Item1); tuple.Item2.Dispose(); _signalStore.Remove((signalDefinition, callback)); } @@ -33,7 +33,7 @@ private void DisposeClosures() { foreach (var item in _signalStore.Values) { - Internal.Functions.SignalHandlerDisconnect(Handle, item.Item1); + Internal.Functions.SignalHandlerDisconnect(Handle.DangerousGetHandle(), item.Item1); item.Item2.Dispose(); } diff --git a/src/Libs/GObject-2.0/Public/Object.cs b/src/Libs/GObject-2.0/Public/Object.cs index 5b4fd48ba..114b3dc5a 100644 --- a/src/Libs/GObject-2.0/Public/Object.cs +++ b/src/Libs/GObject-2.0/Public/Object.cs @@ -1,77 +1,24 @@ using System; -using System.ComponentModel; using System.Diagnostics; -using System.Linq; -using System.Runtime.CompilerServices; -using GLib; using GObject.Internal; namespace GObject; -public partial class Object : IObject, IDisposable, IHandle +public partial class Object : IDisposable { - private readonly ObjectHandle _handle; + public ObjectHandle Handle { get; } - public IntPtr Handle => _handle.Handle; - - /// - /// Initializes a wrapper for an existing object - /// - /// - /// Defines if the handle is owned by us. If not owned by us it is refed to keep it around. - protected Object(IntPtr handle, bool ownedRef) - { - _handle = new ObjectHandle(handle, this, ownedRef); - Initialize(); - } - - /// - /// Constructs a new object - /// - /// True if the ownership of the resulting resulting handle will be transfered. Otherwise false. - /// - /// This constructor is protected to be sure that there is no caller (enduser) keeping a reference to - /// the construct parameters as the contained values are freed at the end of this constructor. - /// If certain constructors are needed they need to be implemented with concrete constructor arguments in - /// a higher layer. - protected Object(bool owned, ConstructArgument[] constructArguments) - { - Type gtype = GetGTypeOrRegister(GetType()); - - IntPtr handle = Internal.Object.NewWithProperties( - objectType: gtype, - nProperties: (uint) constructArguments.Length, - names: GetNames(constructArguments), - values: ValueArray2OwnedHandle.Create(constructArguments.Select(x => x.Value).ToArray()) - ); - - // We can't check if a reference is floating via "g_object_is_floating" here - // as the function could be "lying" depending on the intent of framework writers. - // E.g. A Gtk.Window created via "g_object_new_with_properties" returns an unowned - // reference which is not marked as floating as the gtk toolkit "owns" it. - // For this reason we just delegate the problem to the caller and require a - // definition wether the ownership of the new object will be transered to us or not. - _handle = new ObjectHandle(handle, this, owned); - - Initialize(); - } - - private string[] GetNames(ConstructArgument[] constructParameters) - => constructParameters.Select(x => x.Name).ToArray(); - - /// - /// Does common initialization tasks. - /// Wrapper and subclasses can override here to perform immediate initialization. - /// - protected virtual void Initialize() + protected Object(ObjectHandle handle) { - Debug.WriteLine($"Handle {_handle.Handle}: Initialising object of type {GetType()}."); + Handle = handle; + Handle.Cache(this); + Handle.AddMemoryPressure(); } - public virtual void Dispose() + public void Dispose() { - Debug.WriteLine($"Handle {_handle.Handle}: Disposing object of type {GetType()}."); + Debug.WriteLine($"Handle {Handle.DangerousGetHandle()}: Disposing object of type {GetType()}."); DisposeClosures(); - _handle.Dispose(); + Handle.Dispose(); } } diff --git a/src/Libs/GObject-2.0/Public/Property.cs b/src/Libs/GObject-2.0/Public/Property.cs index 18e9a98d1..c048d3b47 100644 --- a/src/Libs/GObject-2.0/Public/Property.cs +++ b/src/Libs/GObject-2.0/Public/Property.cs @@ -56,7 +56,7 @@ public void Set(K obj, T value) if (obj is not Object o) throw new ArgumentException($"Can't set property {ManagedName} for object of type {typeof(K).Name} as it is not derived from {nameof(Object)}."); - var type = GetPropertyType(o.Handle); + var type = GetPropertyType(o.Handle.DangerousGetHandle()); using var gvalue = new Value(type); gvalue.Set(value); diff --git a/src/Libs/GObject-2.0/Public/ReturningSignalTSender.cs b/src/Libs/GObject-2.0/Public/ReturningSignalTSender.cs index ddd5237d1..1ff7d0f5f 100644 --- a/src/Libs/GObject-2.0/Public/ReturningSignalTSender.cs +++ b/src/Libs/GObject-2.0/Public/ReturningSignalTSender.cs @@ -20,11 +20,7 @@ public ReturningSignal(string unmanagedName, string managedName) private uint GetId() { -#if NET7_0_OR_GREATER var gType = TSender.GetGType(); -#else - var gType = Internal.GTypeProviderHelper.GetGType(); -#endif return Internal.Functions.SignalLookup(GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(UnmanagedName), gType); } diff --git a/src/Libs/GObject-2.0/Public/ReturningSignalTSenderTSignalArgs.cs b/src/Libs/GObject-2.0/Public/ReturningSignalTSenderTSignalArgs.cs index 00711d487..3b7ed7061 100644 --- a/src/Libs/GObject-2.0/Public/ReturningSignalTSenderTSignalArgs.cs +++ b/src/Libs/GObject-2.0/Public/ReturningSignalTSenderTSignalArgs.cs @@ -21,11 +21,7 @@ public ReturningSignal(string unmanagedName, string managedName) private uint GetId() { -#if NET7_0_OR_GREATER var gType = TSender.GetGType(); -#else - var gType = Internal.GTypeProviderHelper.GetGType(); -#endif return Internal.Functions.SignalLookup(GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(UnmanagedName), gType); } diff --git a/src/Libs/GObject-2.0/Public/SignalTSender.cs b/src/Libs/GObject-2.0/Public/SignalTSender.cs index ac8979739..fa313c627 100644 --- a/src/Libs/GObject-2.0/Public/SignalTSender.cs +++ b/src/Libs/GObject-2.0/Public/SignalTSender.cs @@ -20,11 +20,7 @@ public Signal(string unmanagedName, string managedName) private uint GetId() { -#if NET7_0_OR_GREATER var gType = TSender.GetGType(); -#else - var gType = Internal.GTypeProviderHelper.GetGType(); -#endif return Internal.Functions.SignalLookup(GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(UnmanagedName), gType); } diff --git a/src/Libs/GObject-2.0/Public/SignalTSenderTSignalArgs.cs b/src/Libs/GObject-2.0/Public/SignalTSenderTSignalArgs.cs index eef4a30e5..72ae7f059 100644 --- a/src/Libs/GObject-2.0/Public/SignalTSenderTSignalArgs.cs +++ b/src/Libs/GObject-2.0/Public/SignalTSenderTSignalArgs.cs @@ -21,11 +21,7 @@ public Signal(string unmanagedName, string managedName) private uint GetId() { -#if NET7_0_OR_GREATER var gType = TSender.GetGType(); -#else - var gType = Internal.GTypeProviderHelper.GetGType(); -#endif return Internal.Functions.SignalLookup(GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(UnmanagedName), gType); } diff --git a/src/Libs/GObject-2.0/Public/Value.cs b/src/Libs/GObject-2.0/Public/Value.cs index 723a17345..c39e0ebb3 100644 --- a/src/Libs/GObject-2.0/Public/Value.cs +++ b/src/Libs/GObject-2.0/Public/Value.cs @@ -1,6 +1,5 @@ using System; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using GLib.Internal; using GObject.Internal; diff --git a/src/Libs/Gdk-4.0/Public/Clipboard.cs b/src/Libs/Gdk-4.0/Public/Clipboard.cs index 20442b7f3..cb4c8f00f 100644 --- a/src/Libs/Gdk-4.0/Public/Clipboard.cs +++ b/src/Libs/Gdk-4.0/Public/Clipboard.cs @@ -18,7 +18,7 @@ public partial class Clipboard return; } - var readValue = Internal.Clipboard.ReadTextFinish(sourceObject.Handle, res.Handle, out var error); + var readValue = Internal.Clipboard.ReadTextFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); @@ -27,7 +27,7 @@ public partial class Clipboard }); Internal.Clipboard.ReadTextAsync( - clipboard: Handle, + clipboard: Handle.DangerousGetHandle(), cancellable: IntPtr.Zero, callback: callbackHandler.NativeCallback, userData: IntPtr.Zero diff --git a/src/Libs/GdkPixbuf-2.0/Internal/PixbufHandle.cs b/src/Libs/GdkPixbuf-2.0/Internal/PixbufHandle.cs new file mode 100644 index 000000000..474d566d0 --- /dev/null +++ b/src/Libs/GdkPixbuf-2.0/Internal/PixbufHandle.cs @@ -0,0 +1,19 @@ +using System; + +namespace GdkPixbuf.Internal; + +public partial class PixbufHandle +{ + private long _size; + + protected override void AddMemoryPressure() + { + _size = (long) Pixbuf.GetByteLength(handle); + GC.AddMemoryPressure(_size); + } + + protected override void RemoveMemoryPressure() + { + GC.RemoveMemoryPressure(_size); + } +} diff --git a/src/Libs/GdkPixbuf-2.0/Public/Pixbuf.cs b/src/Libs/GdkPixbuf-2.0/Public/Pixbuf.cs deleted file mode 100644 index 8b78c952f..000000000 --- a/src/Libs/GdkPixbuf-2.0/Public/Pixbuf.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using GLib; - -namespace GdkPixbuf; - -public partial class Pixbuf -{ - #region Fields - - private long _size; - - #endregion - - protected override void Initialize() - { - base.Initialize(); - _size = (long) Internal.Pixbuf.GetByteLength(Handle); - GC.AddMemoryPressure(_size); - } - - public override void Dispose() - { - base.Dispose(); - GC.RemoveMemoryPressure(_size); - } -} diff --git a/src/Libs/GdkPixbuf-2.0/Public/PixbufLoader.cs b/src/Libs/GdkPixbuf-2.0/Public/PixbufLoader.cs deleted file mode 100644 index c65291a99..000000000 --- a/src/Libs/GdkPixbuf-2.0/Public/PixbufLoader.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using GLib; - -namespace GdkPixbuf; - -public partial class PixbufLoader -{ - public static Pixbuf FromBytes(byte[] data) - { - IntPtr handle = Internal.PixbufLoader.New(); - - try - { - using var bytes = Bytes.New(data); - - Internal.PixbufLoader.WriteBytes(handle, bytes.Handle, out var error); - - if (!error.IsInvalid) - throw new GException(error); - - Internal.PixbufLoader.Close(handle, out error); - - if (!error.IsInvalid) - throw new GException(error); - - return new Pixbuf(Internal.PixbufLoader.GetPixbuf(handle), false); - } - finally - { - GObject.Internal.Object.Unref(handle); - } - } -} diff --git a/src/Libs/Gio-2.0/Public/DBusConnection.cs b/src/Libs/Gio-2.0/Public/DBusConnection.cs index 860366edf..cb021fcb9 100644 --- a/src/Libs/Gio-2.0/Public/DBusConnection.cs +++ b/src/Libs/Gio-2.0/Public/DBusConnection.cs @@ -13,7 +13,7 @@ public static DBusConnection Get(BusType busType) if (!error.IsInvalid) throw new GException(error); - return GObject.Internal.ObjectWrapper.WrapHandle(handle, true); + return (DBusConnection) GObject.Internal.InstanceWrapper.WrapHandle(handle, true); } public Task CallAsync(string busName, string objectPath, string interfaceName, string methodName, @@ -29,7 +29,7 @@ public Task CallAsync(string busName, string objectPath, string interfa return; } - var ret = Internal.DBusConnection.CallFinish(sourceObject.Handle, res.Handle, out var error); + var ret = Internal.DBusConnection.CallFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GException(error)); @@ -37,7 +37,7 @@ public Task CallAsync(string busName, string objectPath, string interfa tcs.SetResult(new Variant(ret)); }); - Internal.DBusConnection.Call(Handle, + Internal.DBusConnection.Call(Handle.DangerousGetHandle(), GLib.Internal.NullableUtf8StringOwnedHandle.Create(busName), GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(objectPath), GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(interfaceName), GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(methodName), (GLib.Internal.VariantHandle?) parameters?.Handle ?? GLib.Internal.VariantUnownedHandle.NullHandle, GLib.Internal.VariantTypeUnownedHandle.NullHandle, DBusCallFlags.None, -1, IntPtr.Zero, callbackHandler.NativeCallback, IntPtr.Zero); diff --git a/src/Libs/Gio-2.0/Public/Module.cs b/src/Libs/Gio-2.0/Public/Module.cs index 02ffdaa69..9cafcd727 100644 --- a/src/Libs/Gio-2.0/Public/Module.cs +++ b/src/Libs/Gio-2.0/Public/Module.cs @@ -26,11 +26,14 @@ public static void Initialize() if (IsInitialized) return; + // Set immediately as initialized as static constructors like from Gio.Application + // which get called during "TypeRegistration.RegisterTypes" will call this method again + // resulting in a double execution. A second try would probably make no difference. + IsInitialized = true; + GObject.Module.Initialize(); Internal.ImportResolver.RegisterAsDllImportResolver(); Internal.TypeRegistration.RegisterTypes(); - - IsInitialized = true; } } diff --git a/src/Libs/Gtk-4.0/Public/AlertDialog.cs b/src/Libs/Gtk-4.0/Public/AlertDialog.cs index 9eaa53d88..801c196af 100644 --- a/src/Libs/Gtk-4.0/Public/AlertDialog.cs +++ b/src/Libs/Gtk-4.0/Public/AlertDialog.cs @@ -18,7 +18,7 @@ public Task ChooseAsync(Window parent) return; } - var chooseValue = Internal.AlertDialog.ChooseFinish(sourceObject.Handle, res.Handle, out var error); + var chooseValue = Internal.AlertDialog.ChooseFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); @@ -27,8 +27,8 @@ public Task ChooseAsync(Window parent) }); Internal.AlertDialog.Choose( - self: Handle, - parent: parent.Handle, + self: Handle.DangerousGetHandle(), + parent: parent.Handle.DangerousGetHandle(), cancellable: IntPtr.Zero, callback: callbackHandler.NativeCallback, userData: IntPtr.Zero diff --git a/src/Libs/Gtk-4.0/Public/Builder.cs b/src/Libs/Gtk-4.0/Public/Builder.cs index 1f162f6f4..c9203206a 100644 --- a/src/Libs/Gtk-4.0/Public/Builder.cs +++ b/src/Libs/Gtk-4.0/Public/Builder.cs @@ -3,13 +3,15 @@ using System.Linq; using System.Reflection; using System.Text; +using GObject.Internal; +using Gtk.Internal; namespace Gtk; public partial class Builder { #region Constructors - private Builder(string templateXml, bool owned) : this(Internal.Builder.NewFromString(GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(templateXml), Encoding.UTF8.GetByteCount(templateXml)), owned) + private Builder(string templateXml, bool owned) : this(new BuilderHandle(Internal.Builder.NewFromString(GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(templateXml), Encoding.UTF8.GetByteCount(templateXml)), owned)) { } public Builder(string embeddedTemplateName) : this(GetTemplate(Assembly.GetCallingAssembly(), embeddedTemplateName), true) @@ -32,7 +34,7 @@ private void ConnectSignals(object obj) public IntPtr GetPointer(string name) { - return Internal.Builder.GetObject(this.Handle, GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(name)); + return Internal.Builder.GetObject(this.Handle.DangerousGetHandle(), GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(name)); } /* @@ -85,39 +87,16 @@ private void ConnectFields(object obj) if (!typeof(Widget).IsAssignableFrom(field.FieldType)) throw new Exception($"{field.FieldType.Name} must be a {nameof(Widget)}"); - var constructor = field.FieldType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) - .Where(CheckConstructor) - .FirstOrDefault(); - - if (constructor is null) - throw new Exception($"{field.ReflectedType?.FullName} Field {field.Name}: Could not find a constructor with one parameter of {nameof(IntPtr)} to create a {field.FieldType.FullName}"); - var ptr = GetPointer(element); if (ptr == IntPtr.Zero) throw new Exception($"{field.ReflectedType?.FullName} Field {field.Name}: Could not find an element in the template with the name {element}"); - var newElement = constructor.Invoke(new object[] { ptr, false }); + var newElement = InstanceWrapper.WrapHandle(ptr, false); field.SetValue(obj, newElement); } } - private bool CheckConstructor(ConstructorInfo constructorInfo) - { - var parameters = constructorInfo.GetParameters(); - - if (parameters.Length != 2) - return false; - - if (parameters[0].ParameterType != typeof(IntPtr)) - return false; - - if (parameters[1].ParameterType != typeof(bool)) - return false; - - return true; - } - private static string GetTemplate(Assembly assembly, string template) { using Stream? stream = assembly.GetManifestResourceStream(template); diff --git a/src/Libs/Gtk-4.0/Public/FileDialog.cs b/src/Libs/Gtk-4.0/Public/FileDialog.cs index 35606506b..480cf8d6c 100644 --- a/src/Libs/Gtk-4.0/Public/FileDialog.cs +++ b/src/Libs/Gtk-4.0/Public/FileDialog.cs @@ -18,19 +18,19 @@ public partial class FileDialog return; } - var fileValue = Internal.FileDialog.OpenFinish(sourceObject.Handle, res.Handle, out var error); + var fileValue = Internal.FileDialog.OpenFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); else if (fileValue == IntPtr.Zero) tcs.SetResult(null); else - tcs.SetResult(new Gio.FileHelper(fileValue, true)); + tcs.SetResult((Gio.File) GObject.Internal.InstanceWrapper.WrapHandle(fileValue, true)); }); Internal.FileDialog.Open( - self: Handle, - parent: parent.Handle, + self: Handle.DangerousGetHandle(), + parent: parent.Handle.DangerousGetHandle(), cancellable: IntPtr.Zero, callback: callbackHandler.NativeCallback, userData: IntPtr.Zero @@ -52,17 +52,19 @@ public partial class FileDialog return; } - var listValue = Internal.FileDialog.OpenMultipleFinish(sourceObject.Handle, res.Handle, out var error); + var listValue = Internal.FileDialog.OpenMultipleFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); + else if (listValue == IntPtr.Zero) + tcs.SetResult(null); else - tcs.SetResult(GObject.Internal.ObjectWrapper.WrapNullableInterfaceHandle(listValue, true)); + tcs.SetResult((Gio.ListModel) GObject.Internal.InstanceWrapper.WrapHandle(listValue, true)); }); Internal.FileDialog.OpenMultiple( - self: Handle, - parent: parent.Handle, + self: Handle.DangerousGetHandle(), + parent: parent.Handle.DangerousGetHandle(), cancellable: IntPtr.Zero, callback: callbackHandler.NativeCallback, userData: IntPtr.Zero @@ -84,19 +86,19 @@ public partial class FileDialog return; } - var fileValue = Internal.FileDialog.SaveFinish(sourceObject.Handle, res.Handle, out var error); + var fileValue = Internal.FileDialog.SaveFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); else if (fileValue == IntPtr.Zero) tcs.SetResult(null); else - tcs.SetResult(new Gio.FileHelper(fileValue, true)); + tcs.SetResult((Gio.File) GObject.Internal.InstanceWrapper.WrapHandle(fileValue, true)); }); Internal.FileDialog.Save( - self: Handle, - parent: parent.Handle, + self: Handle.DangerousGetHandle(), + parent: parent.Handle.DangerousGetHandle(), cancellable: IntPtr.Zero, callback: callbackHandler.NativeCallback, userData: IntPtr.Zero @@ -119,19 +121,19 @@ public partial class FileDialog return; } - var fileValue = Internal.FileDialog.SelectFolderFinish(sourceObject.Handle, res.Handle, out var error); + var fileValue = Internal.FileDialog.SelectFolderFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); else if (fileValue == IntPtr.Zero) tcs.SetResult(null); else - tcs.SetResult(new Gio.FileHelper(fileValue, true)); + tcs.SetResult((Gio.File) GObject.Internal.InstanceWrapper.WrapHandle(fileValue, true)); }); Internal.FileDialog.SelectFolder( - self: Handle, - parent: parent.Handle, + self: Handle.DangerousGetHandle(), + parent: parent.Handle.DangerousGetHandle(), cancellable: IntPtr.Zero, callback: callbackHandler.NativeCallback, userData: IntPtr.Zero @@ -153,17 +155,19 @@ public partial class FileDialog return; } - var listValue = Internal.FileDialog.SelectMultipleFoldersFinish(sourceObject.Handle, res.Handle, out var error); + var listValue = Internal.FileDialog.SelectMultipleFoldersFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); + else if (listValue == IntPtr.Zero) + tcs.SetResult(null); else - tcs.SetResult(GObject.Internal.ObjectWrapper.WrapNullableInterfaceHandle(listValue, true)); + tcs.SetResult((Gio.ListModel) GObject.Internal.InstanceWrapper.WrapHandle(listValue, true)); }); Internal.FileDialog.SelectMultipleFolders( - self: Handle, - parent: parent.Handle, + self: Handle.DangerousGetHandle(), + parent: parent.Handle.DangerousGetHandle(), cancellable: IntPtr.Zero, callback: callbackHandler.NativeCallback, userData: IntPtr.Zero diff --git a/src/Libs/Gtk-4.0/Public/FileLauncher.cs b/src/Libs/Gtk-4.0/Public/FileLauncher.cs index 7dafb5b23..efe402efe 100644 --- a/src/Libs/Gtk-4.0/Public/FileLauncher.cs +++ b/src/Libs/Gtk-4.0/Public/FileLauncher.cs @@ -18,7 +18,7 @@ public Task LaunchAsync(Window parent) return; } - var launchValue = Internal.FileLauncher.LaunchFinish(sourceObject.Handle, res.Handle, out var error); + var launchValue = Internal.FileLauncher.LaunchFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); @@ -27,8 +27,8 @@ public Task LaunchAsync(Window parent) }); Internal.FileLauncher.Launch( - self: Handle, - parent: parent.Handle, + self: Handle.DangerousGetHandle(), + parent: parent.Handle.DangerousGetHandle(), cancellable: IntPtr.Zero, callback: callbackHandler.NativeCallback, userData: IntPtr.Zero @@ -50,7 +50,7 @@ public Task OpenContainingFolderAsync(Window parent) return; } - var launchValue = Internal.FileLauncher.OpenContainingFolderFinish(sourceObject.Handle, res.Handle, out var error); + var launchValue = Internal.FileLauncher.OpenContainingFolderFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); @@ -59,8 +59,8 @@ public Task OpenContainingFolderAsync(Window parent) }); Internal.FileLauncher.OpenContainingFolder( - self: Handle, - parent: parent.Handle, + self: Handle.DangerousGetHandle(), + parent: parent.Handle.DangerousGetHandle(), cancellable: IntPtr.Zero, callback: callbackHandler.NativeCallback, userData: IntPtr.Zero diff --git a/src/Libs/Gtk-4.0/Public/FontDialog.cs b/src/Libs/Gtk-4.0/Public/FontDialog.cs index 745042f4d..8ad53ca7f 100644 --- a/src/Libs/Gtk-4.0/Public/FontDialog.cs +++ b/src/Libs/Gtk-4.0/Public/FontDialog.cs @@ -18,21 +18,20 @@ public partial class FontDialog return; } - var chooseFontFaceResult = Internal.FontDialog.ChooseFaceFinish(sourceObject.Handle, res.Handle, out var error); + var chooseFontFaceResult = Internal.FontDialog.ChooseFaceFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); + if (chooseFontFaceResult == IntPtr.Zero) + tcs.SetResult(null); else - { - var result = GObject.Internal.ObjectWrapper.WrapNullableHandle(chooseFontFaceResult, false); - tcs.SetResult(result); - } + tcs.SetResult((Pango.FontFace) GObject.Internal.InstanceWrapper.WrapHandle(chooseFontFaceResult, true)); }); Internal.FontDialog.ChooseFace( - Handle, - parent.Handle, - fontFace?.Handle ?? IntPtr.Zero, + Handle.DangerousGetHandle(), + parent.Handle.DangerousGetHandle(), + fontFace?.Handle.DangerousGetHandle() ?? IntPtr.Zero, IntPtr.Zero, callbackHandler.NativeCallback, IntPtr.Zero @@ -54,21 +53,20 @@ public partial class FontDialog return; } - var chooseFontFamilyResult = Internal.FontDialog.ChooseFamilyFinish(sourceObject.Handle, res.Handle, out var error); + var chooseFontFamilyResult = Internal.FontDialog.ChooseFamilyFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); + else if (chooseFontFamilyResult == IntPtr.Zero) + tcs.SetResult(null); else - { - var result = GObject.Internal.ObjectWrapper.WrapNullableHandle(chooseFontFamilyResult, false); - tcs.SetResult(result); - } + tcs.SetResult((Pango.FontFamily) GObject.Internal.InstanceWrapper.WrapHandle(chooseFontFamilyResult, true)); }); Internal.FontDialog.ChooseFamily( - Handle, - parent.Handle, - fontFamily?.Handle ?? IntPtr.Zero, + Handle.DangerousGetHandle(), + parent.Handle.DangerousGetHandle(), + fontFamily?.Handle.DangerousGetHandle() ?? IntPtr.Zero, IntPtr.Zero, callbackHandler.NativeCallback, IntPtr.Zero @@ -90,26 +88,20 @@ public partial class FontDialog return; } - var fontDescriptionOwnedHandle = Internal.FontDialog.ChooseFontFinish(sourceObject.Handle, res.Handle, out var error); + var fontDescriptionOwnedHandle = Internal.FontDialog.ChooseFontFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); + else if (fontDescriptionOwnedHandle.IsInvalid) + tcs.SetResult(null); else - { - if (fontDescriptionOwnedHandle.IsInvalid) - tcs.SetResult(null); - else - { - var result = new Pango.FontDescription(fontDescriptionOwnedHandle); - tcs.SetResult(result); - } - } + tcs.SetResult(new Pango.FontDescription(fontDescriptionOwnedHandle)); }); var initialValue = (Pango.Internal.FontDescriptionHandle?) fontDescription?.Handle ?? Pango.Internal.FontDescriptionUnownedHandle.NullHandle; Internal.FontDialog.ChooseFont( - Handle, - parent.Handle, + Handle.DangerousGetHandle(), + parent.Handle.DangerousGetHandle(), initialValue, IntPtr.Zero, callbackHandler.NativeCallback, diff --git a/src/Libs/Gtk-4.0/Public/Module.cs b/src/Libs/Gtk-4.0/Public/Module.cs index a763df9be..87531b7f6 100644 --- a/src/Libs/Gtk-4.0/Public/Module.cs +++ b/src/Libs/Gtk-4.0/Public/Module.cs @@ -32,6 +32,11 @@ public static void Initialize() if (IsInitialized) return; + // Set immediately as initialized as static constructors like from Gio.Application + // which get called during "TypeRegistration.RegisterTypes" will call this method again + // resulting in a double execution. A second try would probably make no difference. + IsInitialized = true; + Gdk.Module.Initialize(); Gsk.Module.Initialize(); diff --git a/src/Libs/Gtk-4.0/Public/UriLauncher.cs b/src/Libs/Gtk-4.0/Public/UriLauncher.cs index 514d8e1f2..39d3bee6e 100644 --- a/src/Libs/Gtk-4.0/Public/UriLauncher.cs +++ b/src/Libs/Gtk-4.0/Public/UriLauncher.cs @@ -18,7 +18,7 @@ public Task LaunchAsync(Window parent) return; } - var launchValue = Internal.UriLauncher.LaunchFinish(sourceObject.Handle, res.Handle, out var error); + var launchValue = Internal.UriLauncher.LaunchFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); @@ -27,8 +27,8 @@ public Task LaunchAsync(Window parent) }); Internal.UriLauncher.Launch( - self: Handle, - parent: parent.Handle, + self: Handle.DangerousGetHandle(), + parent: parent.Handle.DangerousGetHandle(), cancellable: IntPtr.Zero, callback: callbackHandler.NativeCallback, userData: IntPtr.Zero diff --git a/src/Libs/WebKit-6.0/Public/WebView.cs b/src/Libs/WebKit-6.0/Public/WebView.cs index 5e97eb7a1..a893647b4 100644 --- a/src/Libs/WebKit-6.0/Public/WebView.cs +++ b/src/Libs/WebKit-6.0/Public/WebView.cs @@ -18,16 +18,16 @@ public partial class WebView return; } - var jsValue = Internal.WebView.EvaluateJavascriptFinish(sourceObject.Handle, res.Handle, out var error); + var jsValue = Internal.WebView.EvaluateJavascriptFinish(sourceObject.Handle.DangerousGetHandle(), res.Handle.DangerousGetHandle(), out var error); if (!error.IsInvalid) tcs.SetException(new GLib.GException(error)); else - tcs.SetResult(GObject.Internal.ObjectWrapper.WrapHandle(jsValue, true)); + tcs.SetResult((JavaScriptCore.Value) GObject.Internal.InstanceWrapper.WrapHandle(jsValue, true)); }); Internal.WebView.EvaluateJavascript( - webView: Handle, + webView: Handle.DangerousGetHandle(), script: GLib.Internal.NonNullableUtf8StringOwnedHandle.Create(script), length: -1, worldName: GLib.Internal.NullableUtf8StringOwnedHandle.Create(null), diff --git a/src/Native/GirTestLib/data/girtest-executor-private-impl.c b/src/Native/GirTestLib/data/girtest-executor-private-impl.c new file mode 100644 index 000000000..102aa5f7d --- /dev/null +++ b/src/Native/GirTestLib/data/girtest-executor-private-impl.c @@ -0,0 +1,42 @@ +#include "girtest-executor-private-impl.h" + +#define GIRTEST_TYPE_EXECUTOR_PRIVATE_IMPL girtest_executor_private_impl_get_type() + +struct _GirTestExecutorPrivateImpl +{ + GObject parent_instance; +}; + +static void girtest_executor_private_impl_interface_init (GirTestExecutorInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (GirTestExecutorPrivateImpl, girtest_executor_private_impl, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GIRTEST_TYPE_EXECUTOR, + girtest_executor_private_impl_interface_init)) + +static void +girtest_executor_private_impl_exec (GirTestExecutor *self) +{ + g_print ("Called: exec\n"); +} + +static void +girtest_executor_private_impl_interface_init (GirTestExecutorInterface *iface) +{ + iface->exec = girtest_executor_private_impl_exec; +} + +static void +girtest_executor_private_impl_init(GirTestExecutorPrivateImpl *value) +{ +} + +static void +girtest_executor_private_impl_class_init(GirTestExecutorPrivateImplClass *class) +{ +} + +GirTestExecutorPrivateImpl* +girtest_executor_private_impl_new () +{ + return g_object_new (GIRTEST_TYPE_EXECUTOR_PRIVATE_IMPL, NULL); +} \ No newline at end of file diff --git a/src/Native/GirTestLib/data/girtest-executor-private-impl.h b/src/Native/GirTestLib/data/girtest-executor-private-impl.h new file mode 100644 index 000000000..ae1df521e --- /dev/null +++ b/src/Native/GirTestLib/data/girtest-executor-private-impl.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include "girtest-executor.h" + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(GirTestExecutorPrivateImpl, girtest_executor_private_impl, GIRTEST, EXECUTOR_PRIVATE_IMPL, GObject) + +GirTestExecutorPrivateImpl* +girtest_executor_private_impl_new (); + +G_END_DECLS diff --git a/src/Native/GirTestLib/girtest-property-tester.c b/src/Native/GirTestLib/girtest-property-tester.c index d7a60e322..06321a47e 100644 --- a/src/Native/GirTestLib/girtest-property-tester.c +++ b/src/Native/GirTestLib/girtest-property-tester.c @@ -1,5 +1,7 @@ #include "girtest-property-tester.h" #include "girtest-typed-record-tester.h" +#include "data/girtest-executor-impl.h" +#include "data/girtest-executor-private-impl.h" /** * GirTestPropertyTester: @@ -14,6 +16,9 @@ typedef enum PROP_TYPED_RECORD_VALUE = 3, PROP_INT_VALUE = 4, PROP_BOOLEAN_VALUE = 5, + PROP_OBJECT_VALUE = 6, + PROP_EXECUTOR_VALUE = 7, + PROP_EXECUTOR_ANONYMOUS_VALUE = 8, N_PROPERTIES } PropertyTesterProperty; @@ -21,11 +26,15 @@ struct _GirTestPropertyTester { GObject parent_instance; - gchar *string_value; - gchar *property_tester; + gchar* string_value; + gchar* property_tester; GirTestTypedRecordTester* record; + GObject* object_value; + GirTestExecutor* executor_value; + GirTestExecutor* executor_anonymous_value; gint int_value; gboolean boolean_value; + }; G_DEFINE_TYPE(GirTestPropertyTester, girtest_property_tester, G_TYPE_OBJECT) @@ -58,6 +67,15 @@ girtest_property_tester_get_property (GObject *object, case PROP_BOOLEAN_VALUE: g_value_set_boolean (value, self->boolean_value); break; + case PROP_OBJECT_VALUE: + g_value_set_object (value, self->object_value); + break; + case PROP_EXECUTOR_VALUE: + g_value_set_object (value, self->executor_value); + break; + case PROP_EXECUTOR_ANONYMOUS_VALUE: + g_value_set_object (value, self->executor_anonymous_value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -88,6 +106,9 @@ girtest_property_tester_set_property (GObject *object, case PROP_BOOLEAN_VALUE: self->boolean_value = g_value_get_boolean (value); break; + case PROP_OBJECT_VALUE: + self->object_value = g_value_get_object (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -96,6 +117,8 @@ girtest_property_tester_set_property (GObject *object, static void girtest_property_tester_init(GirTestPropertyTester *value) { + value->executor_value = GIRTEST_EXECUTOR(girtest_executor_impl_new()); + value->executor_anonymous_value = GIRTEST_EXECUTOR(girtest_executor_private_impl_new()); } static void @@ -127,6 +150,26 @@ girtest_property_tester_class_init(GirTestPropertyTesterClass *class) properties[PROP_TYPED_RECORD_VALUE] = g_param_spec_boxed ("record-value", NULL, NULL, GIRTEST_TYPE_TYPED_RECORD_TESTER, G_PARAM_READWRITE); + properties[PROP_OBJECT_VALUE] = + g_param_spec_object ("object-value", + "Object Value", + "An object value", + G_TYPE_OBJECT, + G_PARAM_READWRITE); + + properties[PROP_EXECUTOR_VALUE] = + g_param_spec_object ("executor-value", + "Executor Value", + "An executor value", + GIRTEST_TYPE_EXECUTOR, + G_PARAM_READABLE); + + properties[PROP_EXECUTOR_ANONYMOUS_VALUE] = + g_param_spec_object ("executor-anonymous-value", + "Executor Anonymous Value", + "An executor value", + GIRTEST_TYPE_EXECUTOR, + G_PARAM_READABLE); properties[PROP_INT_VALUE] = g_param_spec_int ("int-value", diff --git a/src/Native/GirTestLib/girtest.h b/src/Native/GirTestLib/girtest.h index e6296643d..f7820a233 100644 --- a/src/Native/GirTestLib/girtest.h +++ b/src/Native/GirTestLib/girtest.h @@ -31,3 +31,4 @@ #include "girtest-utf8-string-array-null-terminated-tester.h" #include "data/girtest-executor.h" #include "data/girtest-executor-impl.h" +#include "data/girtest-executor-private-impl.h" diff --git a/src/Native/GirTestLib/meson.build b/src/Native/GirTestLib/meson.build index c7ccce963..740a071ac 100644 --- a/src/Native/GirTestLib/meson.build +++ b/src/Native/GirTestLib/meson.build @@ -34,9 +34,13 @@ header_files = [ 'girtest-untyped-record-tester.h', 'girtest-utf8-string-array-null-terminated-tester.h', 'data/girtest-executor.h', - 'data/girtest-executor-impl.h', + 'data/girtest-executor-impl.h' ] +header_files_private = [ + 'data/girtest-executor-private-impl.h' +] + source_files = [ 'girtest-alias-tester.c', 'girtest-bitfield-tester.c', @@ -67,12 +71,16 @@ source_files = [ 'girtest-untyped-record-tester.c', 'girtest-utf8-string-array-null-terminated-tester.c', 'data/girtest-executor.c', - 'data/girtest-executor-impl.c', + 'data/girtest-executor-impl.c' +] + +soruce_files_private = [ + 'data/girtest-executor-private-impl.c' ] # Build a shared library that depends on gobject. lib = library('girtest', - source_files, + source_files + soruce_files_private, dependencies: [gobject_dep], install: true ) diff --git a/src/Properties/GirCore.Libraries.props b/src/Properties/GirCore.Libraries.props index 3daf1db32..2cfa07837 100644 --- a/src/Properties/GirCore.Libraries.props +++ b/src/Properties/GirCore.Libraries.props @@ -1,7 +1,7 @@ - net6.0;net7.0;net8.0 + net8.0;net9.0 enable true true diff --git a/src/Properties/GirCore.Tooling.props b/src/Properties/GirCore.Tooling.props index 02d834b74..e72df6640 100644 --- a/src/Properties/GirCore.Tooling.props +++ b/src/Properties/GirCore.Tooling.props @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable true diff --git a/src/Samples/Adw-1/Window/Window.csproj b/src/Samples/Adw-1/Window/Window.csproj index 20b422599..76c54e551 100644 --- a/src/Samples/Adw-1/Window/Window.csproj +++ b/src/Samples/Adw-1/Window/Window.csproj @@ -6,7 +6,7 @@ Exe - net6.0 + net8.0 enable diff --git a/src/Samples/GdkPixbuf-2.0/TestLoading/Program.cs b/src/Samples/GdkPixbuf-2.0/TestLoading/Program.cs deleted file mode 100644 index d8bba6087..000000000 --- a/src/Samples/GdkPixbuf-2.0/TestLoading/Program.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using GdkPixbuf; - -Console.WriteLine("Testing Pixbuf"); - -try -{ - Module.Initialize(); - var pixbuf = Pixbuf.NewFromFile("test.bmp"); - - Console.WriteLine("Loaded Pixbuf at address " + pixbuf.Handle); - Console.WriteLine("Width: " + pixbuf.Width); - Console.WriteLine("Height: " + pixbuf.Height); - Console.WriteLine("Has Alpha: " + pixbuf.HasAlpha); - Console.WriteLine("Channels: " + pixbuf.NChannels); - - Console.WriteLine("Done!"); -} -catch (Exception e) -{ - Console.WriteLine($"Test Failed: {e.Message}"); -} diff --git a/src/Samples/GdkPixbuf-2.0/TestLoading/TestLoading.csproj b/src/Samples/GdkPixbuf-2.0/TestLoading/TestLoading.csproj deleted file mode 100644 index d1445e488..000000000 --- a/src/Samples/GdkPixbuf-2.0/TestLoading/TestLoading.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - Exe - net6.0 - - - - - - - - - - - diff --git a/src/Samples/GdkPixbuf-2.0/TestLoading/test.bmp b/src/Samples/GdkPixbuf-2.0/TestLoading/test.bmp deleted file mode 100644 index c599257f5d3e227071e798896fcdd4e0c7d79172..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 750054 zcmeIup%H*U3 { - PixbufLoader.FromBytes(imageBytes); + FromBytes(imageBytes); }); } Task.WaitAll(tasks); @@ -55,7 +56,7 @@ public static void Main(string[] args) Console.WriteLine("Bytes finalizer: Memory can go up. GC.Collect() is called in the end which must free everything up."); for (int i = 0; i < cycles; i++) { - var p = PixbufLoader.FromBytes(imageBytes); + var p = FromBytes(imageBytes); } Done(); @@ -72,12 +73,23 @@ public static void Main(string[] args) for (int i = 0; i < cycles; i++) { - var p = PixbufLoader.FromBytes(imageBytes); + var p = FromBytes(imageBytes); p.Dispose(); } Done(); } + private static Pixbuf FromBytes(byte[] data) + { + using var bytes = Bytes.New(data); + var loader = PixbufLoader.New(); + loader.WriteBytes(bytes); + loader.Close(); + + return loader.GetPixbuf() ?? throw new Exception("No Pixbuf created."); + + } + private static void Done() { Console.WriteLine("DONE."); diff --git a/src/Samples/GdkPixbuf-2.0/TestMemoryLeaks/TestMemoryLeaks.csproj b/src/Samples/GdkPixbuf-2.0/TestMemoryLeaks/TestMemoryLeaks.csproj index b6d5df728..4246e8406 100644 --- a/src/Samples/GdkPixbuf-2.0/TestMemoryLeaks/TestMemoryLeaks.csproj +++ b/src/Samples/GdkPixbuf-2.0/TestMemoryLeaks/TestMemoryLeaks.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net8.0 enable diff --git a/src/Samples/Gio-2.0/DBus/DBus.csproj b/src/Samples/Gio-2.0/DBus/DBus.csproj index 34cf605ee..9350572d7 100644 --- a/src/Samples/Gio-2.0/DBus/DBus.csproj +++ b/src/Samples/Gio-2.0/DBus/DBus.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net8.0 DBus diff --git a/src/Samples/Gst-1.0/VideoPlayback/VideoPlayback.csproj b/src/Samples/Gst-1.0/VideoPlayback/VideoPlayback.csproj index 76ff17fdc..d8e8ea578 100644 --- a/src/Samples/Gst-1.0/VideoPlayback/VideoPlayback.csproj +++ b/src/Samples/Gst-1.0/VideoPlayback/VideoPlayback.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net8.0 GStreamer diff --git a/src/Samples/Gtk-4.0/AboutDialog/AboutDialog.csproj b/src/Samples/Gtk-4.0/AboutDialog/AboutDialog.csproj index 9c0ac4494..e26f560ba 100644 --- a/src/Samples/Gtk-4.0/AboutDialog/AboutDialog.csproj +++ b/src/Samples/Gtk-4.0/AboutDialog/AboutDialog.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net8.0 diff --git a/src/Samples/Gtk-4.0/AboutDialog/SampleAboutDialog.cs b/src/Samples/Gtk-4.0/AboutDialog/SampleAboutDialog.cs index ca0707a56..f15b31da7 100644 --- a/src/Samples/Gtk-4.0/AboutDialog/SampleAboutDialog.cs +++ b/src/Samples/Gtk-4.0/AboutDialog/SampleAboutDialog.cs @@ -1,6 +1,7 @@ using System; using System.Reflection; using GdkPixbuf; +using GLib; using GObject; namespace AboutDialog; @@ -24,8 +25,13 @@ private static Gdk.Texture LoadFromResource(string resourceName) { try { - var bytes = Assembly.GetExecutingAssembly().ReadResourceAsByteArray(resourceName); - var pixbuf = PixbufLoader.FromBytes(bytes); + var data = Assembly.GetExecutingAssembly().ReadResourceAsByteArray(resourceName); + using var bytes = Bytes.New(data); + var pixbufLoader = PixbufLoader.New(); + pixbufLoader.WriteBytes(bytes); + pixbufLoader.Close(); + + var pixbuf = pixbufLoader.GetPixbuf() ?? throw new Exception("No pixbuf loaded"); return Gdk.Texture.NewForPixbuf(pixbuf); } catch (Exception e) diff --git a/src/Samples/Gtk-4.0/Builder/Builder.csproj b/src/Samples/Gtk-4.0/Builder/Builder.csproj index 1e8b5c8d3..ad10aeb98 100644 --- a/src/Samples/Gtk-4.0/Builder/Builder.csproj +++ b/src/Samples/Gtk-4.0/Builder/Builder.csproj @@ -6,7 +6,7 @@ Exe - net6.0 + net8.0 enable diff --git a/src/Samples/Gtk-4.0/Builder/SampleTestDialog.cs b/src/Samples/Gtk-4.0/Builder/SampleTestDialog.cs index 515e01619..22ac52267 100644 --- a/src/Samples/Gtk-4.0/Builder/SampleTestDialog.cs +++ b/src/Samples/Gtk-4.0/Builder/SampleTestDialog.cs @@ -1,19 +1,17 @@ -using Gtk; +namespace BuilderSample; -namespace BuilderSample; - -public class SampleTestDialog : Dialog +public class SampleTestDialog : Gtk.Dialog { - [Connect] private readonly Button okButton; + [Gtk.Connect] private readonly Gtk.Button okButton; - private SampleTestDialog(Builder builder, string name) : base(builder.GetPointer(name), false) + private SampleTestDialog(Gtk.Builder builder, string name) : base(new Gtk.Internal.DialogHandle(builder.GetPointer(name), false)) { builder.Connect(this); - okButton.OnClicked += (_, _) => this.Response((int) ResponseType.Ok); + okButton.OnClicked += (_, _) => this.Response((int) Gtk.ResponseType.Ok); } - public SampleTestDialog() : this(new Builder("SampleTestDialog.4.ui"), "dialog") + public SampleTestDialog() : this(new Gtk.Builder("SampleTestDialog.4.ui"), "dialog") { } } diff --git a/src/Samples/Gtk-4.0/DrawingArea/DrawingArea.csproj b/src/Samples/Gtk-4.0/DrawingArea/DrawingArea.csproj index e7da48baf..fddd153a0 100644 --- a/src/Samples/Gtk-4.0/DrawingArea/DrawingArea.csproj +++ b/src/Samples/Gtk-4.0/DrawingArea/DrawingArea.csproj @@ -1,7 +1,7 @@ - net6.0 + net8.0 Exe diff --git a/src/Samples/Gtk-4.0/FontDialog/FontDialog.csproj b/src/Samples/Gtk-4.0/FontDialog/FontDialog.csproj index f767743ba..70494dac4 100644 --- a/src/Samples/Gtk-4.0/FontDialog/FontDialog.csproj +++ b/src/Samples/Gtk-4.0/FontDialog/FontDialog.csproj @@ -6,7 +6,7 @@ Exe - net6.0 + net8.0 enable diff --git a/src/Samples/Gtk-4.0/GridView/CustomObjectGridViewWindow.cs b/src/Samples/Gtk-4.0/GridView/CustomObjectGridViewWindow.cs index 1acb641d4..005905608 100644 --- a/src/Samples/Gtk-4.0/GridView/CustomObjectGridViewWindow.cs +++ b/src/Samples/Gtk-4.0/GridView/CustomObjectGridViewWindow.cs @@ -1,24 +1,35 @@ using System; +using GObject; +using GObject.Internal; using Gtk; using static Gtk.GridView; using static Gtk.SignalListItemFactory; using ListStore = Gio.ListStore; +using Type = GObject.Type; namespace GridViewSample; -public class ItemData : GObject.Object +public class ItemData : GObject.Object, GTypeProvider, InstanceFactory { - public string ImagePath { get; set; } - public string Text { get; set; } - public string Description { get; set; } + private static readonly Type GType = SubclassRegistrar.Register(); + public static new Type GetGType() => GType; + static object InstanceFactory.Create(IntPtr handle, bool ownsHandle) + { + return new ItemData(handle, ownsHandle); + } - public ItemData(string imagePath, string text, string description) - : base(true, Array.Empty()) + public string? ImagePath { get; set; } + public string? Text { get; set; } + public string? Description { get; set; } + + public ItemData(string imagePath, string text, string description) : base(ObjectHandle.For(true, [])) { ImagePath = imagePath; Text = text; Description = description; } + + private ItemData(IntPtr ptr, bool ownsHandle) : base(new ObjectHandle(ptr, ownsHandle)) { } } public class CustomObjectGridViewWindow : Window diff --git a/src/Samples/Gtk-4.0/GridView/GridView.csproj b/src/Samples/Gtk-4.0/GridView/GridView.csproj index 46e44ff30..c24d63834 100644 --- a/src/Samples/Gtk-4.0/GridView/GridView.csproj +++ b/src/Samples/Gtk-4.0/GridView/GridView.csproj @@ -10,7 +10,7 @@ Exe - net6.0 + net8.0 enable diff --git a/src/Samples/Gtk-4.0/GridView/StringListGridViewWindow.cs b/src/Samples/Gtk-4.0/GridView/StringListGridViewWindow.cs index 6d6f0c8cc..e91ddda5b 100644 --- a/src/Samples/Gtk-4.0/GridView/StringListGridViewWindow.cs +++ b/src/Samples/Gtk-4.0/GridView/StringListGridViewWindow.cs @@ -10,7 +10,7 @@ public StringListGridViewWindow() Title = "Gtk::GridView (Gio::ListStore)"; SetDefaultSize(400, 400); - var stringList = StringList.New(new string[] { "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten" }); + var stringList = StringList.New(["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"]); var selectionModel = NoSelection.New(stringList); var listItemFactory = SignalListItemFactory.New(); listItemFactory.OnSetup += SetupSignalHandler; diff --git a/src/Samples/Gtk-4.0/ListView/ListView.csproj b/src/Samples/Gtk-4.0/ListView/ListView.csproj index 950a67f89..216634ccf 100644 --- a/src/Samples/Gtk-4.0/ListView/ListView.csproj +++ b/src/Samples/Gtk-4.0/ListView/ListView.csproj @@ -6,7 +6,7 @@ Exe - net6.0 + net8.0 enable enable diff --git a/src/Samples/Gtk-4.0/ListView/TemplateListViewWindow.cs b/src/Samples/Gtk-4.0/ListView/TemplateListViewWindow.cs index 0f834244e..22f7dfe36 100644 --- a/src/Samples/Gtk-4.0/ListView/TemplateListViewWindow.cs +++ b/src/Samples/Gtk-4.0/ListView/TemplateListViewWindow.cs @@ -12,7 +12,7 @@ public TemplateListViewWindow() Title = "Template ListView"; SetDefaultSize(300, 300); - var stringList = StringList.New(new string[] { "One", "Two", "Three", "Four" }); + var stringList = StringList.New(["One", "Two", "Three", "Four"]); var selectionModel = SingleSelection.New(stringList); var bytes = Assembly.GetExecutingAssembly() .ReadResourceAsByteArray("ListItemTemplate.ui"); diff --git a/src/Samples/Gtk-4.0/Window/Window.csproj b/src/Samples/Gtk-4.0/Window/Window.csproj index f767743ba..70494dac4 100644 --- a/src/Samples/Gtk-4.0/Window/Window.csproj +++ b/src/Samples/Gtk-4.0/Window/Window.csproj @@ -6,7 +6,7 @@ Exe - net6.0 + net8.0 enable diff --git a/src/Samples/GtkSource-5/GtkSourceView/GtkSourceView.csproj b/src/Samples/GtkSource-5/GtkSourceView/GtkSourceView.csproj index 738d81bbc..a8bab9547 100644 --- a/src/Samples/GtkSource-5/GtkSourceView/GtkSourceView.csproj +++ b/src/Samples/GtkSource-5/GtkSourceView/GtkSourceView.csproj @@ -7,7 +7,7 @@ Exe - net6.0 + net8.0 enable diff --git a/src/Samples/WebKit-6.0/JavascriptCall/JavascriptCall.csproj b/src/Samples/WebKit-6.0/JavascriptCall/JavascriptCall.csproj index 400d5f32c..aa0f214c2 100644 --- a/src/Samples/WebKit-6.0/JavascriptCall/JavascriptCall.csproj +++ b/src/Samples/WebKit-6.0/JavascriptCall/JavascriptCall.csproj @@ -7,7 +7,7 @@ Exe - net7.0 + net8.0 enable diff --git a/src/Samples/WebKit-6.0/JavascriptCallback/JavascriptCallback.csproj b/src/Samples/WebKit-6.0/JavascriptCallback/JavascriptCallback.csproj index 400d5f32c..aa0f214c2 100644 --- a/src/Samples/WebKit-6.0/JavascriptCallback/JavascriptCallback.csproj +++ b/src/Samples/WebKit-6.0/JavascriptCallback/JavascriptCallback.csproj @@ -7,7 +7,7 @@ Exe - net7.0 + net8.0 enable diff --git a/src/Tests/Directory.Build.props b/src/Tests/Directory.Build.props deleted file mode 100644 index 1124feb38..000000000 --- a/src/Tests/Directory.Build.props +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - false - - \ No newline at end of file diff --git a/src/Tests/Generation/Directory.Build.props b/src/Tests/Generation/Directory.Build.props new file mode 100644 index 000000000..5968b3fff --- /dev/null +++ b/src/Tests/Generation/Directory.Build.props @@ -0,0 +1,8 @@ + + + + + + false + + \ No newline at end of file diff --git a/src/Tests/Generation/GirLoader.Tests/GirLoader.Tests.csproj b/src/Tests/Generation/GirLoader.Tests/GirLoader.Tests.csproj index 60a04d5cd..76386f65d 100644 --- a/src/Tests/Generation/GirLoader.Tests/GirLoader.Tests.csproj +++ b/src/Tests/Generation/GirLoader.Tests/GirLoader.Tests.csproj @@ -1,6 +1,6 @@ - net8.0 + net9.0 diff --git a/src/Tests/Libs/Directory.Build.props b/src/Tests/Libs/Directory.Build.props new file mode 100644 index 000000000..0b01565d4 --- /dev/null +++ b/src/Tests/Libs/Directory.Build.props @@ -0,0 +1,8 @@ + + + + + + false + + \ No newline at end of file diff --git a/src/Tests/Libs/GObject-2.0.Tests/Classes/GenericTypeRegistrationTests.cs b/src/Tests/Libs/GObject-2.0.Tests/Classes/GenericTypeRegistrationTests.cs index fcf6cbd26..5ec4e7a7e 100644 --- a/src/Tests/Libs/GObject-2.0.Tests/Classes/GenericTypeRegistrationTests.cs +++ b/src/Tests/Libs/GObject-2.0.Tests/Classes/GenericTypeRegistrationTests.cs @@ -1,35 +1,60 @@ using System; +using GObject.Internal; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace GObject.Tests.Classes; -internal class GenericClass : GObject.Object +internal class GenericClass : GObject.Object, GTypeProvider, InstanceFactory { - public GenericClass() : base(true, Array.Empty()) + private static readonly Type GType = SubclassRegistrar.Register(); + public static new Type GetGType() => GType; + static object InstanceFactory.Create(IntPtr handle, bool ownsHandle) { + return new GenericClass(handle, ownsHandle); } + + public GenericClass() : base(ObjectHandle.For(true, [])) { } + private GenericClass(IntPtr ptr, bool ownsHandle) : base(new ObjectHandle(ptr, ownsHandle)) { } } -internal class GenericClass : GObject.Object +internal class GenericClass : GObject.Object, GTypeProvider, InstanceFactory { - public GenericClass() : base(true, Array.Empty()) + private static readonly Type GType = SubclassRegistrar.Register, Object>(); + public static new Type GetGType() => GType; + static object InstanceFactory.Create(IntPtr handle, bool ownsHandle) { + return new GenericClass(handle, ownsHandle); } + + public GenericClass() : base(ObjectHandle.For>(true, [])) { } + private GenericClass(IntPtr ptr, bool ownsHandle) : base(new ObjectHandle(ptr, ownsHandle)) { } } -internal class GenericClass : GObject.Object +internal class GenericClass : GObject.Object, GTypeProvider, InstanceFactory { - public GenericClass() : base(true, Array.Empty()) + private static readonly Type GType = SubclassRegistrar.Register, Object>(); + public static new Type GetGType() => GType; + static object InstanceFactory.Create(IntPtr handle, bool ownsHandle) { + return new GenericClass(handle, ownsHandle); } + + public GenericClass() : base(ObjectHandle.For>(true, [])) { } + private GenericClass(IntPtr ptr, bool ownsHandle) : base(new ObjectHandle(ptr, ownsHandle)) { } } [TestClass, TestCategory("UnitTest")] public class GenericTypeRegistrationTests { - private class NestedGenericClass : GObject.Object + private class NestedGenericClass : GObject.Object, GTypeProvider, InstanceFactory { - public NestedGenericClass() : base(true, Array.Empty()) + private static readonly Type GType = SubclassRegistrar.Register, Object>(); + public static new Type GetGType() => GType; + static object InstanceFactory.Create(IntPtr handle, bool ownsHandle) { + return new NestedGenericClass(handle, ownsHandle); } + + public NestedGenericClass() : base(ObjectHandle.For>(true, [])) { } + private NestedGenericClass(IntPtr ptr, bool ownsHandle) : base(new ObjectHandle(ptr, ownsHandle)) { } } [TestMethod] diff --git a/src/Tests/Libs/GObject-2.0.Tests/Records/TypeTest.cs b/src/Tests/Libs/GObject-2.0.Tests/Records/TypeTest.cs index 2ca4b1a40..9e2cc58cb 100644 --- a/src/Tests/Libs/GObject-2.0.Tests/Records/TypeTest.cs +++ b/src/Tests/Libs/GObject-2.0.Tests/Records/TypeTest.cs @@ -22,9 +22,9 @@ public void FundamentalTypesCanBeDetected() Internal.Functions.IsFundamental(255 << 2).Should().BeTrue(); //Fundamental types - Internal.Functions.IsFundamental(Object.GetGType().Value).Should().BeTrue(); + Internal.Functions.IsFundamental(Internal.Object.GetGType()).Should().BeTrue(); //Non fundamental types - Internal.Functions.IsFundamental(Binding.GetGType().Value).Should().BeFalse(); + Internal.Functions.IsFundamental(Internal.Binding.GetGType()).Should().BeFalse(); } } diff --git a/src/Tests/Libs/Gio-2.0.Tests/DBusConnectionTest.cs b/src/Tests/Libs/Gio-2.0.Tests/DBusConnectionTest.cs deleted file mode 100644 index 1831360cf..000000000 --- a/src/Tests/Libs/Gio-2.0.Tests/DBusConnectionTest.cs +++ /dev/null @@ -1,15 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Gio.Tests; - -[TestClass, TestCategory("SystemTest")] -public class DBusConnectionTest : Test -{ - [TestMethod] - public void GetSessionBusShouldNotBeNull() - { - var obj = DBusConnection.Get(BusType.Session); - obj.Should().NotBeNull(); - } -} diff --git a/src/Tests/Libs/GirTest-0.1.Tests/CallbackTest.cs b/src/Tests/Libs/GirTest-0.1.Tests/CallbackTest.cs index ed4e9d369..8571dda77 100644 --- a/src/Tests/Libs/GirTest-0.1.Tests/CallbackTest.cs +++ b/src/Tests/Libs/GirTest-0.1.Tests/CallbackTest.cs @@ -140,7 +140,7 @@ GObject.Type Callback() [TestMethod] public void SupportsCallbackWithObjectReturn() { - var testObject = new TestClass(); + var testObject = ExecutorImpl.New(); GObject.Object Callback() { return testObject; @@ -150,11 +150,6 @@ GObject.Object Callback() obj.Should().Be(testObject); } - private class TestClass : GObject.Object - { - public TestClass() : base(true, System.Array.Empty()) { } - } - [TestMethod] public void SupportsCallbackWithInterfaceReturn() { diff --git a/src/Tests/Libs/GirTest-0.1.Tests/ClassTest.cs b/src/Tests/Libs/GirTest-0.1.Tests/ClassTest.cs index 62244fc67..cec4b6ed3 100644 --- a/src/Tests/Libs/GirTest-0.1.Tests/ClassTest.cs +++ b/src/Tests/Libs/GirTest-0.1.Tests/ClassTest.cs @@ -50,15 +50,15 @@ public void CanTransferOwnershipOfInterfaces() var obj = ClassTester.New(); var executor = GirTest.ExecutorImpl.New(); - var instanceData = Marshal.PtrToStructure(executor.Handle); + var instanceData = Marshal.PtrToStructure(executor.Handle.DangerousGetHandle()); instanceData.RefCount.Should().Be(1); obj.TakeExecutor(executor); - instanceData = Marshal.PtrToStructure(executor.Handle); + instanceData = Marshal.PtrToStructure(executor.Handle.DangerousGetHandle()); instanceData.RefCount.Should().Be(2); obj.FreeExecutor(); - instanceData = Marshal.PtrToStructure(executor.Handle); + instanceData = Marshal.PtrToStructure(executor.Handle.DangerousGetHandle()); instanceData.RefCount.Should().Be(1); } @@ -66,9 +66,9 @@ public void CanTransferOwnershipOfInterfaces() public void TestManualGObjectDisposal() { var obj = ClassTester.New(); - GObject.Internal.ObjectMapper.ObjectCount.Should().Be(1); + GObject.Internal.InstanceCache.ObjectCount.Should().Be(1); obj.Dispose(); - GObject.Internal.ObjectMapper.ObjectCount.Should().Be(0); + GObject.Internal.InstanceCache.ObjectCount.Should().Be(0); } [TestMethod] @@ -80,18 +80,18 @@ public void TestAutomaticGObjectDisposal() CollectAfter(() => { var obj = ClassTester.New(); - GObject.Internal.ObjectMapper.ObjectCount.Should().Be(1); + GObject.Internal.InstanceCache.ObjectCount.Should().Be(1); weakReference.Target = obj; }); - GObject.Internal.ObjectMapper.ObjectCount.Should().Be(0); + GObject.Internal.InstanceCache.ObjectCount.Should().Be(0); weakReference.IsAlive.Should().BeFalse(); CollectAfter(() => { var obj = ClassTester.New(); - GObject.Internal.ObjectMapper.ObjectCount.Should().Be(1); + GObject.Internal.InstanceCache.ObjectCount.Should().Be(1); strongReference = obj; weakReference.Target = obj; diff --git a/src/Tests/Libs/GirTest-0.1.Tests/OpaqueTypedRecordTest.cs b/src/Tests/Libs/GirTest-0.1.Tests/OpaqueTypedRecordTest.cs index 070a57275..c6c1070ca 100644 --- a/src/Tests/Libs/GirTest-0.1.Tests/OpaqueTypedRecordTest.cs +++ b/src/Tests/Libs/GirTest-0.1.Tests/OpaqueTypedRecordTest.cs @@ -303,7 +303,7 @@ public void SupportsWrapHandle() var wrapped = (OpaqueTypedRecordTester) GObject.Internal.BoxedWrapper.WrapHandle( handle: recordTester.Handle.DangerousGetHandle(), ownsHandle: false, - gtype: OpaqueTypedRecordTester.GetGType() + gtype: Internal.OpaqueTypedRecordTester.GetGType() ); wrapped.Handle.DangerousGetHandle().Should().Be(recordTester.Handle.DangerousGetHandle()); diff --git a/src/Tests/Libs/GirTest-0.1.Tests/PropertyTest.cs b/src/Tests/Libs/GirTest-0.1.Tests/PropertyTest.cs index bf249d610..e01ac1889 100644 --- a/src/Tests/Libs/GirTest-0.1.Tests/PropertyTest.cs +++ b/src/Tests/Libs/GirTest-0.1.Tests/PropertyTest.cs @@ -1,4 +1,5 @@ -using FluentAssertions; +using System.Reflection; +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace GirTest.Tests; @@ -98,4 +99,45 @@ public void TestBooleanProperty(bool b) obj.BooleanValue.Should().Be(b); } + + [TestMethod] + public void TestObjectProperty() + { + var o = new PropertyTester(); + + var obj = PropertyTester.New(); + obj.ObjectValue.Should().BeNull(); + obj.ObjectValue = o; + obj.ObjectValue.Should().Be(o); + obj.ObjectValue = null; + obj.ObjectValue.Should().BeNull(); + } + + [TestMethod] + public void SupportsReadOnlyProperty() + { + var property = typeof(PropertyTester).GetProperty(nameof(PropertyTester.ExecutorValue)); + property.Should().BeReadable(); + property.Should().NotBeWritable(); + } + + [TestMethod] + public void PrefersKnownTypeForInterfaceReturnInsteadOfHelper() + { + var property = typeof(PropertyTester).GetProperty(nameof(PropertyTester.ExecutorValue)); + property.Should().Return(typeof(Executor)); + + var obj = PropertyTester.New(); + obj.ExecutorValue.Should().BeOfType(); + } + + [TestMethod] + public void FallsBackToInterfaceHelperForUnknownTypesWhichImplementAnInterface() + { + var property = typeof(PropertyTester).GetProperty(nameof(PropertyTester.ExecutorAnonymousValue)); + property.Should().Return(typeof(Executor)); + + var obj = PropertyTester.New(); + obj.ExecutorAnonymousValue.Should().BeOfType(); + } } diff --git a/src/Tests/Libs/GirTest-0.1.Tests/TypedRecordTest.cs b/src/Tests/Libs/GirTest-0.1.Tests/TypedRecordTest.cs index 72462292e..8c1c0b741 100644 --- a/src/Tests/Libs/GirTest-0.1.Tests/TypedRecordTest.cs +++ b/src/Tests/Libs/GirTest-0.1.Tests/TypedRecordTest.cs @@ -303,7 +303,7 @@ public void SupportsWrapHandle() var wrapped = (TypedRecordTester) GObject.Internal.BoxedWrapper.WrapHandle( handle: recordTester.Handle.DangerousGetHandle(), ownsHandle: false, - gtype: TypedRecordTester.GetGType() + gtype: Internal.TypedRecordTester.GetGType() ); wrapped.Handle.DangerousGetHandle().Should().Be(recordTester.Handle.DangerousGetHandle()); diff --git a/src/Tests/Libs/Gtk-4.0.Tests/PropertyTests.cs b/src/Tests/Libs/Gtk-4.0.Tests/PropertyTests.cs index b18e547ce..47c3efd46 100644 --- a/src/Tests/Libs/Gtk-4.0.Tests/PropertyTests.cs +++ b/src/Tests/Libs/Gtk-4.0.Tests/PropertyTests.cs @@ -73,17 +73,4 @@ public void TestEnum(License windowPosition) aboutDialog.LicenseType.Should().Be(windowPosition); } - - [TestMethod] - public void TestObject() - { - var pixbuf = GdkPixbuf.Pixbuf.NewFromFile("test.bmp") ?? throw new Exception("Missing image"); - var texture = Gdk.Texture.NewForPixbuf(pixbuf); - var dialog = new AboutDialog(); - dialog.Logo.Should().BeNull(); - dialog.Logo = texture; - dialog.Logo.Should().Be(texture); - dialog.Logo = null!; - dialog.Logo.Should().BeNull(); - } }