From 03154120308606a38f369b19204eaaeb5d440710 Mon Sep 17 00:00:00 2001 From: badcel <1218031+badcel@users.noreply.github.com> Date: Wed, 11 Jan 2023 15:18:14 +0100 Subject: [PATCH] Support detailed signals Detailed signals are providing some kind of filtering for signals. See: https://docs.gtk.org/gobject/concepts.html#the-detail-argument --- .../Generator/Public/Class/ClassFunctions.cs | 3 +- .../InterfaceImplementationFramework.cs | 2 ++ .../Internal/GTypeProviderHelper.cs | 20 +++++++++++ src/Libs/GObject-2.0/Public/Object.Signals.cs | 5 +-- .../GObject-2.0/Public/SignalDefinition.cs | 9 +++-- src/Libs/GObject-2.0/Public/SignalTSender.cs | 35 ++++++++++++------- .../Public/SignalTSenderTSignalArgs.cs | 29 ++++++++++----- 7 files changed, 77 insertions(+), 26 deletions(-) create mode 100644 src/Libs/GObject-2.0/Internal/GTypeProviderHelper.cs diff --git a/src/Generation/Generator/Generator/Public/Class/ClassFunctions.cs b/src/Generation/Generator/Generator/Public/Class/ClassFunctions.cs index 7f0512ba8..7570876d4 100644 --- a/src/Generation/Generator/Generator/Public/Class/ClassFunctions.cs +++ b/src/Generation/Generator/Generator/Public/Class/ClassFunctions.cs @@ -17,8 +17,7 @@ public void Generate(GirModel.Class obj) if (obj.Fundamental) return; - if (!obj.Functions.Any()) - return; + //There is always at least the type function (GetGType) available var source = Renderer.Public.ClassFunctions.Render(obj); var codeUnit = new CodeUnit( diff --git a/src/Generation/Generator/Generator/Public/InterfaceImplementation/InterfaceImplementationFramework.cs b/src/Generation/Generator/Generator/Public/InterfaceImplementation/InterfaceImplementationFramework.cs index 12cdf8157..a07888119 100644 --- a/src/Generation/Generator/Generator/Public/InterfaceImplementation/InterfaceImplementationFramework.cs +++ b/src/Generation/Generator/Generator/Public/InterfaceImplementation/InterfaceImplementationFramework.cs @@ -13,6 +13,8 @@ public InterfaceImplementationFramework(Publisher publisher) public void Generate(GirModel.Interface obj) { + //There is always at least the type function (GetGType) available + var source = Renderer.Public.InterfaceImplementationFramework.Render(obj); var codeUnit = new CodeUnit( Project: Namespace.GetCanonicalName(obj.Namespace), diff --git a/src/Libs/GObject-2.0/Internal/GTypeProviderHelper.cs b/src/Libs/GObject-2.0/Internal/GTypeProviderHelper.cs new file mode 100644 index 000000000..158765c0a --- /dev/null +++ b/src/Libs/GObject-2.0/Internal/GTypeProviderHelper.cs @@ -0,0 +1,20 @@ +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 nuint 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 (nuint) (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/Public/Object.Signals.cs b/src/Libs/GObject-2.0/Public/Object.Signals.cs index 1b4446189..ad925a37e 100644 --- a/src/Libs/GObject-2.0/Public/Object.Signals.cs +++ b/src/Libs/GObject-2.0/Public/Object.Signals.cs @@ -7,9 +7,10 @@ public partial class Object { private readonly Dictionary<(SignalDefinition, Delegate), (ulong, Closure)> _signalStore = new(); - internal void SignalConnectClosure(SignalDefinition signalDefinition, Delegate callback, Closure closure, bool after) + internal void SignalConnectClosure(SignalDefinition signalDefinition, Delegate callback, Closure closure, bool after, string? detail) { - var handlerId = Internal.Functions.SignalConnectClosure(Handle, signalDefinition.UnmanagedName, closure.Handle, after); + var detailQuark = GLib.Functions.QuarkFromString(detail); + var handlerId = Internal.Functions.SignalConnectClosureById(Handle, signalDefinition.Id, detailQuark, closure.Handle, after); if (handlerId == 0) throw new Exception($"Could not connect to event {signalDefinition.ManagedName}"); diff --git a/src/Libs/GObject-2.0/Public/SignalDefinition.cs b/src/Libs/GObject-2.0/Public/SignalDefinition.cs index 10e474aa4..276df188b 100644 --- a/src/Libs/GObject-2.0/Public/SignalDefinition.cs +++ b/src/Libs/GObject-2.0/Public/SignalDefinition.cs @@ -5,10 +5,15 @@ public interface SignalDefinition /// /// The name of the signal in GObject/C. /// - public string UnmanagedName { get; } + string UnmanagedName { get; } /// /// The name of the signal in dotnet. /// - public string ManagedName { get; } + string ManagedName { get; } + + /// + /// The Id of the signal in GObject/C + /// + uint Id { get; } } diff --git a/src/Libs/GObject-2.0/Public/SignalTSender.cs b/src/Libs/GObject-2.0/Public/SignalTSender.cs index 65741aeaf..534f13fbd 100644 --- a/src/Libs/GObject-2.0/Public/SignalTSender.cs +++ b/src/Libs/GObject-2.0/Public/SignalTSender.cs @@ -1,15 +1,16 @@ -using System; - -namespace GObject; +namespace GObject; /// /// Describes a GSignal. /// public class Signal : SignalDefinition - where TSender : Object + where TSender : Object, GTypeProvider { + private uint? _id; + public string UnmanagedName { get; } public string ManagedName { get; } + public uint Id => _id ??= GetId(); public Signal(string unmanagedName, string managedName) { @@ -17,23 +18,33 @@ public Signal(string unmanagedName, string managedName) ManagedName = managedName; } + private uint GetId() + { +#if NET7_0_OR_GREATER + var gType = TSender.GetGType(); +#else + var gType = Internal.GTypeProviderHelper.GetGType(); +#endif + + return Internal.Functions.SignalLookup(UnmanagedName, gType); + } + /// - /// Connects an to this signal. + /// Connects a to this signal. /// /// The object on which connect the handler. /// The signal handler function. - /// - /// Define if this action must be called before or after the default handler of this signal. - /// - public void Connect(TSender o, SignalHandler signalHandler, bool after = false) + /// Define if this action must be called before or after the default handler of this signal. + /// Define for which signal detail the connection should be made. + public void Connect(TSender o, SignalHandler signalHandler, bool after = false, string? detail = null) { - var closure = new Closure((returnValue, parameters) => signalHandler(o, EventArgs.Empty)); + var closure = new Closure((returnValue, parameters) => signalHandler(o, System.EventArgs.Empty)); - o.SignalConnectClosure(this, signalHandler, closure, after); + o.SignalConnectClosure(this, signalHandler, closure, after, detail); } /// - /// Disconnects an previously connected to this signal. + /// Disconnects a previously connected to this signal. /// /// The object from which disconnect the handler. /// The signal handler function. diff --git a/src/Libs/GObject-2.0/Public/SignalTSenderTSignalArgs.cs b/src/Libs/GObject-2.0/Public/SignalTSenderTSignalArgs.cs index 754c0f163..80217b9b9 100644 --- a/src/Libs/GObject-2.0/Public/SignalTSenderTSignalArgs.cs +++ b/src/Libs/GObject-2.0/Public/SignalTSenderTSignalArgs.cs @@ -4,11 +4,14 @@ /// Describes a GSignal. /// public class Signal : SignalDefinition - where TSender : Object + where TSender : Object, GTypeProvider where TSignalArgs : SignalArgs, new() { + private uint? _id; + public string UnmanagedName { get; } public string ManagedName { get; } + public uint Id => _id ??= GetId(); public Signal(string unmanagedName, string managedName) { @@ -16,15 +19,25 @@ public Signal(string unmanagedName, string managedName) ManagedName = managedName; } + private uint GetId() + { +#if NET7_0_OR_GREATER + var gType = TSender.GetGType(); +#else + var gType = Internal.GTypeProviderHelper.GetGType(); +#endif + + return Internal.Functions.SignalLookup(UnmanagedName, gType); + } + /// - /// Connects an to this signal. + /// Connects a to this signal. /// /// The object on which connect the handler. /// The signal handler function. - /// - /// Define if this action must be called before or after the default handler of this signal. - /// - public void Connect(TSender o, SignalHandler signalHandler, bool after = false) + /// Define if this action must be called before or after the default handler of this signal. + /// Define for which signal detail the connection should be made. + public void Connect(TSender o, SignalHandler signalHandler, bool after = false, string? detail = null) { var closure = new Closure((returnValue, parameters) => { @@ -33,11 +46,11 @@ public void Connect(TSender o, SignalHandler signalHandler signalHandler(o, args); }); - o.SignalConnectClosure(this, signalHandler, closure, after); + o.SignalConnectClosure(this, signalHandler, closure, after, detail); } /// - /// Disconnects an previously connected to this signal. + /// Disconnects a previously connected to this signal. /// /// The object from which disconnect the handler. /// The signal handler function.