using GtkSharp; namespace Gtk { using System; using System.Runtime.InteropServices; public partial class Container { internal static D TryGetDelegate(IntPtr _cb) { try { var d = Marshal.GetDelegateForFunctionPointer(_cb); return d; } catch { return default; } } static ForAllNativeDelegate ForAll_cb_delegate; static ForAllNativeDelegate ForAllVMCallback { get { if (ForAll_cb_delegate == null) ForAll_cb_delegate = new ForAllNativeDelegate(ForAll_cb); return ForAll_cb_delegate; } } static void OverrideForAll(GLib.GType gtype) { OverrideForAll(gtype, ForAllVMCallback); } /// /// sets callback forall in GtkContainerClass-Struct /// /// /// static void OverrideForAll(GLib.GType gtype, ForAllNativeDelegate callback) { unsafe { IntPtr* raw_ptr = (IntPtr*) (((long) gtype.GetClassPtr()) + (long) class_abi.GetFieldOffset("forall")); *raw_ptr = Marshal.GetFunctionPointerForDelegate(callback); } } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void ForAllNativeDelegate(IntPtr inst, bool include_internals, IntPtr cb, IntPtr data); internal class ForAllCallbackHandler { internal IntPtr cb { get; } internal IntPtr data { get; } internal bool include_internals { get; } internal ForAllCallbackHandler(IntPtr cb, IntPtr data, bool include_internals) { this.cb = cb; this.data = data; this.include_internals = include_internals; } internal void Invoke(Widget w) { var nativeCb = TryGetDelegate(cb); var inv = new GtkSharp.CallbackInvoker(nativeCb, data); inv.Handler?.Invoke(w); } } static void ForAll_cb(IntPtr inst, bool include_internals, IntPtr cb, IntPtr data) { try { //GtkContainer's unmanaged dispose calls forall, but by that time the managed object is gone //so it couldn't do anything useful, and resurrecting it would cause a resurrection cycle. //In that case, just chain to the native base in case it can do something. var fcb = new ForAllCallbackHandler(cb, data, include_internals); if (GLib.Object.TryGetObject(inst) is Container container) { container.ForAll(include_internals, fcb.Invoke); } else { gtksharp_container_base_forall(inst, include_internals, fcb.Invoke, data); } } catch (Exception e) { GLib.ExceptionManager.RaiseUnhandledException(e, false); } } [GLib.DefaultSignalHandler(Type = typeof(Gtk.Container), ConnectionMethod = nameof(OverrideForAll))] protected virtual void ForAll(bool include_internals, Callback callback) { InternalForAll(include_internals, callback); } private void InternalForAll(bool include_internals, Callback callback) { if (!(callback.Target is ForAllCallbackHandler)) { throw new ApplicationException( $"{nameof(ForAll)} can only be called as \"base.{nameof(ForAll)}()\". Use {nameof(Forall)}() or {nameof(Foreach)}()."); } gtksharp_container_base_forall(Handle, include_internals, callback, ((ForAllCallbackHandler) callback.Target).data); } static ForAllNativeDelegate InternalForAllNativeDelegate(GLib.GType gtype) { ForAllNativeDelegate unmanaged = null; unsafe { IntPtr* raw_ptr = (IntPtr*) (((long) gtype.GetClassPtr()) + (long) class_abi.GetFieldOffset("forall")); if (*raw_ptr == IntPtr.Zero) return default; unmanaged = Marshal.GetDelegateForFunctionPointer(*raw_ptr); } return unmanaged; } static void gtksharp_container_base_forall(IntPtr container, bool include_internals, Callback cb, IntPtr data) { // gtksharp_container_base_forall from gtkglue: // Find and call the first base callback that's not the GTK# callback. The GTK# callback calls down the whole // managed override chain, so calling it on a subclass-of-a-managed-container-subclass causes a stack overflow. // GtkContainerClass *parent = (GtkContainerClass *) G_OBJECT_GET_CLASS (container); // while ((parent = g_type_class_peek_parent (parent))) { // if (strncmp (G_OBJECT_CLASS_NAME (parent), "__gtksharp_", 11) != 0) { // if (parent->forall) { // (*parent->forall) (container, include_internals, cb, data); // } // return; // } // } if (container == IntPtr.Zero) return; var obj = TryGetObject(container); if (obj == default) return; var parent = obj.NativeType; while ((parent = parent.GetBaseType()) != GLib.GType.None) { if (parent.ToString().StartsWith("__gtksharp_")) { continue; } var forAll = InternalForAllNativeDelegate(parent); if (forAll != default && cb.Target is ForAllCallbackHandler cbh) { GtkSharp.CallbackWrapper cb_wrapper = new GtkSharp.CallbackWrapper(cb); forAll(container, include_internals, cbh.cb, data); } return; } } } }