/// <summary> /// Connects a callback function (<paramref name="callback"/>) to a signal on this object. /// </summary> /// <remarks> /// The callback will be triggered every time this signal is issued on this instance. /// </remarks> /// <param name="detailedSignal">A string of the form "signal-name::detail".</param> /// <param name="callback">The callback to connect.</param> /// <param name="data">Data to pass to handler calls.</param> /// <returns>The handler id.</returns> /// <exception cref="T:System.Exception">If it failed to connect the signal.</exception> public uint SignalConnect(string detailedSignal, Delegate callback, IntPtr data = default) { if (callback is Image.EvalDelegate evalDelegate) { void EvalMarshal(IntPtr imagePtr, IntPtr progressPtr, IntPtr userDataPtr) { if (progressPtr == IntPtr.Zero || imagePtr == IntPtr.Zero) { return; } using var image = new Image(imagePtr); image.ObjectRef(); var progressStruct = progressPtr.Dereference <VipsProgress>(); evalDelegate.Invoke(image, progressStruct); } callback = (VipsImage.EvalSignal)EvalMarshal; } // add a weak reference callback to ensure all handles are released on finalization if (_handles.Count == 0) { GWeakNotify notify = ReleaseDelegates; var notifyHandle = GCHandle.Alloc(notify); Internal.GObject.WeakRef(this, notify, GCHandle.ToIntPtr(notifyHandle)); } // prevent the delegate from being re-located or disposed of by the garbage collector var delegateHandle = GCHandle.Alloc(callback); _handles.Add(delegateHandle); // get the pointer for the delegate which can be passed to the native code var callbackPtr = Marshal.GetFunctionPointerForDelegate(callback); var ret = GSignal.ConnectData(this, detailedSignal, callbackPtr, data, null, default); if (ret == 0) { throw new Exception("Failed to connect signal."); } return(ret); }
/// <summary> /// Connects a callback function (<paramref name="callback"/>) to a signal on this object. /// </summary> /// <remarks> /// The callback will be triggered every time this signal is issued on this instance. /// </remarks> /// <param name="detailedSignal">A string of the form "signal-name::detail".</param> /// <param name="callback">The callback to connect.</param> /// <param name="data">Data to pass to handler calls.</param> /// <returns>The handler id.</returns> /// <exception cref="T:System.Exception">If it failed to connect the signal.</exception> public uint SignalConnect(string detailedSignal, Delegate callback, IntPtr data = default) { // prevent the delegate from being re-located or disposed of by the garbage collector var delegateHandle = GCHandle.Alloc(callback); _handles.Add(delegateHandle); // get the pointer for the delegate which can be passed to the native code var callbackPtr = Marshal.GetFunctionPointerForDelegate(callback); var ret = GSignal.ConnectData(this, detailedSignal, callbackPtr, data, null, default); if (ret == 0) { throw new Exception("Failed to connect signal."); } return(ret); }