From 4c892094f0da744c45a50e57169cfdfee379ab3b Mon Sep 17 00:00:00 2001 From: Jiyun Yang Date: Fri, 6 Dec 2024 11:18:12 +0900 Subject: [PATCH 1/3] Add method to hold objects to the native life bound Signed-off-by: Jiyun Yang --- src/Tizen.NUI/src/public/Common/BaseHandle.cs | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/src/Tizen.NUI/src/public/Common/BaseHandle.cs b/src/Tizen.NUI/src/public/Common/BaseHandle.cs index b724019f8bc..61cafd19ce8 100755 --- a/src/Tizen.NUI/src/public/Common/BaseHandle.cs +++ b/src/Tizen.NUI/src/public/Common/BaseHandle.cs @@ -15,6 +15,7 @@ * */ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; using Tizen.NUI.Binding; @@ -33,6 +34,8 @@ namespace Tizen.NUI /// 3 public class BaseHandle : Element, global::System.IDisposable { + private static Dictionary> nativeBindedHolder = new Dictionary>(); + static internal void Preload() { // Do nothing. Just call for load static values. @@ -287,7 +290,7 @@ public static explicit operator bool(BaseHandle handle) } /// - /// Logical OR operator for ||. + /// Logical OR operator for ||. /// It's possible when doing a || this function (opBitwiseOr) is never called due to short circuiting. /// /// The first BaseHandle to be compared. @@ -375,7 +378,7 @@ public void Dispose() /// /// Hidden API (Inhouse API). - /// Dispose. + /// Dispose. /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects. /// /// @@ -622,6 +625,9 @@ protected virtual void Dispose(DisposeTypes type) if (SwigCPtr.Handle != IntPtr.Zero) { var nativeSwigCPtr = swigCPtr.Handle; + + ClearHolder(nativeSwigCPtr); + swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero); if (swigCMemOwn) { @@ -654,6 +660,49 @@ protected virtual void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef Interop.BaseHandle.DeleteBaseHandle(swigCPtr.Handle); } + /// + /// Adds the specified object to the set of objects that have been bound to the native object. + /// + /// The object to add. + [EditorBrowsable(EditorBrowsableState.Never)] + protected void AddToNativeHolder(object obj) + { + if (IsDisposedOrQueued) + { + return; + } + + if (!nativeBindedHolder.TryGetValue(swigCPtr.Handle, out var holders)) + { + nativeBindedHolder.Add(swigCPtr.Handle, holders = new HashSet()); + } + + holders.Add(obj); + } + + /// + /// Removes the specified object from the set of objects that have been bound to the native object. + /// + /// The object to remove. + [EditorBrowsable(EditorBrowsableState.Never)] + protected void RemoveFromNativeHolder(object obj) + { + if (IsDisposedOrQueued) + { + return; + } + + if (nativeBindedHolder.TryGetValue(swigCPtr.Handle, out var holders)) + { + holders.Remove(obj); + + if (holders.Count == 0) + { + nativeBindedHolder.Remove(swigCPtr.Handle); + } + } + } + /// /// Contains event arguments for the FocusChangeRequested event. /// @@ -728,6 +777,14 @@ internal bool IsNativeHandleInvalid() [EditorBrowsable(EditorBrowsableState.Never)] protected internal bool IsDisposeQueued => isDisposeQueued; + [EditorBrowsable(EditorBrowsableState.Never)] + protected internal bool IsDisposedOrQueued => disposed || isDisposeQueued; + + static private void ClearHolder(IntPtr handle) + { + nativeBindedHolder.Remove(handle); + } + [Conditional("NUI_DISPOSE_DEBUG_ON")] private void disposeDebuggingCtor() { From df85061d88a92ab3c94fc8e7a3c1ffd3584db851 Mon Sep 17 00:00:00 2001 From: Jiyun Yang Date: Fri, 6 Dec 2024 12:40:00 +0900 Subject: [PATCH 2/3] Make Windows's signal callbacks not collected before native window gone Signed-off-by: Jiyun Yang --- .../src/public/Window/WindowEvent.cs | 127 ++++++++++-------- 1 file changed, 71 insertions(+), 56 deletions(-) diff --git a/src/Tizen.NUI/src/public/Window/WindowEvent.cs b/src/Tizen.NUI/src/public/Window/WindowEvent.cs index 5cb61ef37e4..3cdd9b5f482 100755 --- a/src/Tizen.NUI/src/public/Window/WindowEvent.cs +++ b/src/Tizen.NUI/src/public/Window/WindowEvent.cs @@ -20,6 +20,7 @@ using System.Runtime.InteropServices; using Tizen.NUI.BaseComponents; using System.Collections.Generic; +using System.Diagnostics; namespace Tizen.NUI { @@ -106,7 +107,7 @@ public event EventHandler FocusChanged { if (windowFocusChangedEventHandler == null) { - windowFocusChangedEventCallback = OnWindowFocusedChanged; + CreateSafeCallback(OnWindowFocusedChanged, out windowFocusChangedEventCallback); using WindowFocusSignalType signal = new WindowFocusSignalType(Interop.Window.FocusChangedSignal(SwigCPtr), false); signal.Ensure()?.Connect(windowFocusChangedEventCallback); } @@ -119,7 +120,7 @@ public event EventHandler FocusChanged { using WindowFocusSignalType signal = new WindowFocusSignalType(Interop.Window.FocusChangedSignal(SwigCPtr), false); signal.Ensure()?.Disconnect(windowFocusChangedEventCallback); - windowFocusChangedEventCallback = null; + ReleaseSafeCallback(ref windowFocusChangedEventCallback); } } } @@ -137,7 +138,7 @@ public event EventHandler TouchEvent { if (rootLayerTouchDataEventHandler == null) { - rootLayerTouchDataCallback = OnWindowTouch; + CreateSafeCallback(OnWindowTouch, out rootLayerTouchDataCallback); Interop.ActorSignal.TouchConnect(Layer.getCPtr(GetRootLayer()), rootLayerTouchDataCallback.ToHandleRef(this)); NDalicPINVOKE.ThrowExceptionIfExists(); } @@ -150,7 +151,7 @@ public event EventHandler TouchEvent { Interop.ActorSignal.TouchDisconnect(Layer.getCPtr(GetRootLayer()), rootLayerTouchDataCallback.ToHandleRef(this)); NDalicPINVOKE.ThrowExceptionIfExists(); - rootLayerTouchDataCallback = null; + ReleaseSafeCallback(ref rootLayerTouchDataCallback); } } } @@ -169,7 +170,7 @@ public event ReturnTypeEventHandler InterceptTouch { if (rootLayerInterceptTouchDataEventHandler == null) { - rootLayerInterceptTouchDataCallback = OnWindowInterceptTouch; + CreateSafeCallback(OnWindowInterceptTouch, out rootLayerInterceptTouchDataCallback); Interop.ActorSignal.InterceptTouchConnect(Layer.getCPtr(GetRootLayer()), rootLayerInterceptTouchDataCallback.ToHandleRef(this)); NDalicPINVOKE.ThrowExceptionIfExists(); } @@ -182,7 +183,7 @@ public event ReturnTypeEventHandler InterceptTouch { Interop.ActorSignal.InterceptTouchDisconnect(Layer.getCPtr(GetRootLayer()), rootLayerInterceptTouchDataCallback.ToHandleRef(this)); NDalicPINVOKE.ThrowExceptionIfExists(); - rootLayerInterceptTouchDataCallback = null; + ReleaseSafeCallback(ref rootLayerInterceptTouchDataCallback); } } } @@ -197,7 +198,7 @@ public event EventHandler WheelEvent { if (stageWheelHandler == null) { - wheelEventCallback = OnStageWheel; + CreateSafeCallback(OnStageWheel, out wheelEventCallback); Interop.ActorSignal.WheelEventConnect(Layer.getCPtr(GetRootLayer()), wheelEventCallback.ToHandleRef(this)); NDalicPINVOKE.ThrowExceptionIfExists(); } @@ -205,7 +206,7 @@ public event EventHandler WheelEvent if (DetentEventHandler == null) { - DetentEventCallback = OnDetentEvent; + CreateSafeCallback(OnDetentEvent, out DetentEventCallback); using StageWheelSignal signal = new StageWheelSignal(Interop.StageSignal.WheelEventSignal(stageCPtr), false); signal.Ensure()?.Connect(DetentEventCallback); } @@ -218,7 +219,7 @@ public event EventHandler WheelEvent { Interop.ActorSignal.WheelEventDisconnect(Layer.getCPtr(GetRootLayer()), wheelEventCallback.ToHandleRef(this)); NDalicPINVOKE.ThrowExceptionIfExists(); - wheelEventCallback = null; + ReleaseSafeCallback(ref wheelEventCallback); } DetentEventHandler -= value; @@ -226,7 +227,7 @@ public event EventHandler WheelEvent { using StageWheelSignal signal = new StageWheelSignal(Interop.StageSignal.WheelEventSignal(stageCPtr), false); signal.Ensure()?.Disconnect(DetentEventCallback); - DetentEventCallback = null; + ReleaseSafeCallback(ref DetentEventCallback); } } } @@ -244,7 +245,7 @@ public event ReturnTypeEventHandler InterceptWheel { if (interceptWheelHandler == null) { - interceptWheelCallback = OnWindowInterceptWheel; + CreateSafeCallback(OnWindowInterceptWheel, out interceptWheelCallback); Interop.ActorSignal.InterceptWheelConnect(Layer.getCPtr(GetRootLayer()), interceptWheelCallback.ToHandleRef(this)); NDalicPINVOKE.ThrowExceptionIfExists(); } @@ -257,7 +258,7 @@ public event ReturnTypeEventHandler InterceptWheel { Interop.ActorSignal.InterceptWheelDisconnect(Layer.getCPtr(GetRootLayer()), interceptWheelCallback.ToHandleRef(this)); NDalicPINVOKE.ThrowExceptionIfExists(); - interceptWheelCallback = null; + ReleaseSafeCallback(ref interceptWheelCallback); } } } @@ -272,7 +273,7 @@ public event EventHandler KeyEvent { if (stageKeyHandler == null) { - stageKeyCallbackDelegate = OnStageKey; + CreateSafeCallback(OnStageKey, out stageKeyCallbackDelegate); using KeyEventSignal signal = new KeyEventSignal(Interop.Window.KeyEventSignal(SwigCPtr), false); signal.Ensure()?.Connect(stageKeyCallbackDelegate); } @@ -285,7 +286,7 @@ public event EventHandler KeyEvent { using KeyEventSignal signal = new KeyEventSignal(Interop.Window.KeyEventSignal(SwigCPtr), false); signal.Ensure()?.Disconnect(stageKeyCallbackDelegate); - stageKeyCallbackDelegate = null; + ReleaseSafeCallback(ref stageKeyCallbackDelegate); } } } @@ -301,7 +302,7 @@ public event ReturnTypeEventHandler InterceptKeyEven { if (stageInterceptKeyHandler == null) { - stageInterceptKeyCallbackDelegate = OnStageInterceptKey; + CreateSafeCallback(OnStageInterceptKey, out stageInterceptKeyCallbackDelegate); using KeyEventSignal signal = new KeyEventSignal(Interop.Window.InterceptKeyEventSignal(SwigCPtr), false); signal.Ensure()?.Connect(stageInterceptKeyCallbackDelegate); } @@ -314,7 +315,7 @@ public event ReturnTypeEventHandler InterceptKeyEven { using KeyEventSignal signal = new KeyEventSignal(Interop.Window.InterceptKeyEventSignal(SwigCPtr), false); signal.Ensure()?.Disconnect(stageInterceptKeyCallbackDelegate); - stageInterceptKeyCallbackDelegate = null; + ReleaseSafeCallback(ref stageInterceptKeyCallbackDelegate); } } } @@ -329,7 +330,7 @@ public event EventHandler Resized { if (windowResizeEventHandler == null) { - windowResizeEventCallback = OnResized; + CreateSafeCallback(OnResized, out windowResizeEventCallback); using ResizeSignal signal = new ResizeSignal(Interop.Window.ResizeSignal(SwigCPtr), false); signal.Ensure()?.Connect(windowResizeEventCallback); } @@ -343,7 +344,7 @@ public event EventHandler Resized { using ResizeSignal signal = new ResizeSignal(Interop.Window.ResizeSignal(SwigCPtr), false); signal.Ensure()?.Disconnect(windowResizeEventCallback); - windowResizeEventCallback = null; + ReleaseSafeCallback(ref windowResizeEventCallback); } } } @@ -359,7 +360,7 @@ public event EventHandler HoverEvent { if (rootLayerHoverDataEventHandler == null) { - rootLayerHoverDataCallback = OnWindowHover; + CreateSafeCallback(OnWindowHover, out rootLayerHoverDataCallback); Interop.ActorSignal.HoveredConnect(Layer.getCPtr(GetRootLayer()), rootLayerHoverDataCallback.ToHandleRef(this)); NDalicPINVOKE.ThrowExceptionIfExists(); } @@ -372,7 +373,7 @@ public event EventHandler HoverEvent { Interop.ActorSignal.HoveredDisconnect(Layer.getCPtr(GetRootLayer()), rootLayerHoverDataCallback.ToHandleRef(this)); NDalicPINVOKE.ThrowExceptionIfExists(); - rootLayerHoverDataCallback = null; + ReleaseSafeCallback(ref rootLayerHoverDataCallback); } } } @@ -394,7 +395,7 @@ public event EventHandler WindowFocusChanged { if (windowFocusChangedEventHandler2 == null) { - windowFocusChangedEventCallback2 = OnWindowFocusedChanged2; + CreateSafeCallback(OnWindowFocusedChanged2, out windowFocusChangedEventCallback2); using WindowFocusSignalType signal = new WindowFocusSignalType(Interop.Window.FocusChangedSignal(SwigCPtr), false); signal.Ensure()?.Connect(windowFocusChangedEventCallback2); } @@ -407,7 +408,7 @@ public event EventHandler WindowFocusChanged { using WindowFocusSignalType signal = new WindowFocusSignalType(Interop.Window.FocusChangedSignal(SwigCPtr), false); signal.Ensure()?.Disconnect(windowFocusChangedEventCallback2); - windowFocusChangedEventCallback2 = null; + ReleaseSafeCallback(ref windowFocusChangedEventCallback2); } } } @@ -422,7 +423,7 @@ public event EventHandler TransitionEffect { if (transitionEffectHandler == null) { - transitionEffectEventCallback = OnTransitionEffect; + CreateSafeCallback(OnTransitionEffect, out transitionEffectEventCallback); using WindowTransitionEffectSignal signal = new WindowTransitionEffectSignal(Interop.WindowTransitionEffectSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Connect(transitionEffectEventCallback); } @@ -435,7 +436,7 @@ public event EventHandler TransitionEffect { using WindowTransitionEffectSignal signal = new WindowTransitionEffectSignal(Interop.WindowTransitionEffectSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Disconnect(transitionEffectEventCallback); - transitionEffectEventCallback = null; + ReleaseSafeCallback(ref transitionEffectEventCallback); } } } @@ -450,7 +451,7 @@ public event EventHandler Moved { if (movedHandler == null) { - movedEventCallback = OnMoved; + CreateSafeCallback(OnMoved, out movedEventCallback); using WindowMovedSignal signal = new WindowMovedSignal(Interop.WindowMovedSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Connect(movedEventCallback); } @@ -463,7 +464,7 @@ public event EventHandler Moved { using WindowMovedSignal signal = new WindowMovedSignal(Interop.WindowMovedSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Disconnect(movedEventCallback); - movedEventCallback = null; + ReleaseSafeCallback(ref movedEventCallback); } } } @@ -479,7 +480,7 @@ public event EventHandler OrientationChanged { if (orientationChangedHandler == null) { - orientationChangedEventCallback = OnOrientationChanged; + CreateSafeCallback(OnOrientationChanged, out orientationChangedEventCallback); using WindowOrientationChangedSignal signal = new WindowOrientationChangedSignal(Interop.WindowOrientationChangedSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Connect(orientationChangedEventCallback); } @@ -492,7 +493,7 @@ public event EventHandler OrientationChanged { using WindowOrientationChangedSignal signal = new WindowOrientationChangedSignal(Interop.WindowOrientationChangedSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Disconnect(orientationChangedEventCallback); - orientationChangedEventCallback = null; + ReleaseSafeCallback(ref orientationChangedEventCallback); } } } @@ -507,7 +508,7 @@ public event EventHandler KeyboardRepeatSettingsChanged { if (keyboardRepeatSettingsChangedHandler == null) { - keyboardRepeatSettingsChangedEventCallback = OnKeyboardRepeatSettingsChanged; + CreateSafeCallback(OnKeyboardRepeatSettingsChanged, out keyboardRepeatSettingsChangedEventCallback); using KeyboardRepeatSettingsChangedSignal signal = new KeyboardRepeatSettingsChangedSignal(Interop.KeyboardRepeatSettingsChangedSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Connect(keyboardRepeatSettingsChangedEventCallback); } @@ -520,7 +521,7 @@ public event EventHandler KeyboardRepeatSettingsChanged { using KeyboardRepeatSettingsChangedSignal signal = new KeyboardRepeatSettingsChangedSignal(Interop.KeyboardRepeatSettingsChangedSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Disconnect(keyboardRepeatSettingsChangedEventCallback); - keyboardRepeatSettingsChangedEventCallback = null; + ReleaseSafeCallback(ref keyboardRepeatSettingsChangedEventCallback); } } } @@ -535,7 +536,7 @@ public event EventHandler MouseInOutEvent { if (windowMouseInOutEventHandler == null) { - windowMouseInOutEventCallback = OnWindowMouseInOutEvent; + CreateSafeCallback(OnWindowMouseInOutEvent, out windowMouseInOutEventCallback); using WindowMouseInOutEventSignal signal = new WindowMouseInOutEventSignal(Interop.WindowMouseInOutEventSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Connect(windowMouseInOutEventCallback); } @@ -548,7 +549,7 @@ public event EventHandler MouseInOutEvent { using WindowMouseInOutEventSignal signal = new WindowMouseInOutEventSignal(Interop.WindowMouseInOutEventSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Disconnect(windowMouseInOutEventCallback); - windowMouseInOutEventCallback = null; + ReleaseSafeCallback(ref windowMouseInOutEventCallback); } } } @@ -565,7 +566,7 @@ public event EventHandler MoveCompleted { if (moveCompletedHandler == null) { - moveCompletedEventCallback = OnMoveCompleted; + CreateSafeCallback(OnMoveCompleted, out moveCompletedEventCallback); using WindowMoveCompletedSignal signal = new WindowMoveCompletedSignal(Interop.WindowMoveCompletedSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Connect(moveCompletedEventCallback); } @@ -578,7 +579,7 @@ public event EventHandler MoveCompleted { using WindowMoveCompletedSignal signal = new WindowMoveCompletedSignal(Interop.WindowMoveCompletedSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Disconnect(moveCompletedEventCallback); - moveCompletedEventCallback = null; + ReleaseSafeCallback(ref moveCompletedEventCallback); } } } @@ -595,7 +596,7 @@ public event EventHandler ResizeCompleted { if (resizeCompletedHandler == null) { - resizeCompletedEventCallback = OnResizeCompleted; + CreateSafeCallback(OnResizeCompleted, out resizeCompletedEventCallback); using WindowResizeCompletedSignal signal = new WindowResizeCompletedSignal(Interop.WindowResizeCompletedSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Connect(resizeCompletedEventCallback); } @@ -608,7 +609,7 @@ public event EventHandler ResizeCompleted { using WindowResizeCompletedSignal signal = new WindowResizeCompletedSignal(Interop.WindowResizeCompletedSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Disconnect(resizeCompletedEventCallback); - resizeCompletedEventCallback = null; + ReleaseSafeCallback(ref resizeCompletedEventCallback); } } } @@ -623,7 +624,7 @@ public event EventHandler MouseRelativeEvent { if (windowMouseRelativeEventHandler == null) { - windowMouseRelativeEventCallback = OnWindowMouseRelativeEvent; + CreateSafeCallback(OnWindowMouseRelativeEvent, out windowMouseRelativeEventCallback); using WindowMouseRelativeEventSignal signal = new WindowMouseRelativeEventSignal(Interop.WindowMouseRelativeEventSignal.GetSignal(SwigCPtr), false); signal?.Connect(windowMouseRelativeEventCallback); } @@ -636,7 +637,7 @@ public event EventHandler MouseRelativeEvent { using WindowMouseRelativeEventSignal signal = new WindowMouseRelativeEventSignal(Interop.WindowMouseRelativeEventSignal.GetSignal(SwigCPtr), false); signal?.Disconnect(windowMouseRelativeEventCallback); - windowMouseRelativeEventCallback = null; + ReleaseSafeCallback(ref windowMouseRelativeEventCallback); } } } @@ -651,7 +652,7 @@ public event EventHandler PointerConstraintsEvent { if (windowPointerConstraintsEventHandler == null) { - windowPointerConstraintsEventCallback = OnWindowPointerConstraintsEvent; + CreateSafeCallback(OnWindowPointerConstraintsEvent, out windowPointerConstraintsEventCallback); using WindowPointerConstraintsSignal signal = new WindowPointerConstraintsSignal(Interop.WindowPointerConstraintsSignal.GetSignal(SwigCPtr), false); signal?.Connect(windowPointerConstraintsEventCallback); } @@ -664,7 +665,7 @@ public event EventHandler PointerConstraintsEvent { using WindowPointerConstraintsSignal signal = new WindowPointerConstraintsSignal(Interop.WindowPointerConstraintsSignal.GetSignal(SwigCPtr), false); signal?.Disconnect(windowPointerConstraintsEventCallback); - windowPointerConstraintsEventCallback = null; + ReleaseSafeCallback(ref windowPointerConstraintsEventCallback); } } } @@ -735,7 +736,7 @@ internal event EventHandler EventProcessingFinished { if (stageEventProcessingFinishedEventHandler == null) { - stageEventProcessingFinishedEventCallbackDelegate = OnEventProcessingFinished; + CreateSafeCallback(OnEventProcessingFinished, out stageEventProcessingFinishedEventCallbackDelegate); using VoidSignal signal = new VoidSignal(Interop.StageSignal.EventProcessingFinishedSignal(stageCPtr), false); signal.Ensure()?.Connect(stageEventProcessingFinishedEventCallbackDelegate); } @@ -748,7 +749,7 @@ internal event EventHandler EventProcessingFinished { using VoidSignal signal = new VoidSignal(Interop.StageSignal.EventProcessingFinishedSignal(stageCPtr), false); signal.Ensure()?.Disconnect(stageEventProcessingFinishedEventCallbackDelegate); - stageEventProcessingFinishedEventCallbackDelegate = null; + ReleaseSafeCallback(ref stageEventProcessingFinishedEventCallbackDelegate); } } } @@ -759,7 +760,7 @@ internal event EventHandler ContextLost { if (stageContextLostEventHandler == null) { - stageContextLostEventCallbackDelegate = OnContextLost; + CreateSafeCallback(OnContextLost, out stageContextLostEventCallbackDelegate); using VoidSignal signal = new VoidSignal(Interop.StageSignal.ContextLostSignal(stageCPtr), false); signal.Ensure()?.Connect(stageContextLostEventCallbackDelegate); } @@ -772,7 +773,7 @@ internal event EventHandler ContextLost { using VoidSignal signal = new VoidSignal(Interop.StageSignal.ContextLostSignal(stageCPtr), false); signal.Ensure()?.Disconnect(stageContextLostEventCallbackDelegate); - stageContextLostEventCallbackDelegate = null; + ReleaseSafeCallback(ref stageContextLostEventCallbackDelegate); } } } @@ -783,7 +784,7 @@ internal event EventHandler ContextRegained { if (stageContextRegainedEventHandler == null) { - stageContextRegainedEventCallbackDelegate = OnContextRegained; + CreateSafeCallback(OnContextRegained, out stageContextRegainedEventCallbackDelegate); using VoidSignal signal = new VoidSignal(Interop.StageSignal.ContextRegainedSignal(stageCPtr), false); signal.Ensure()?.Connect(stageContextRegainedEventCallbackDelegate); } @@ -796,7 +797,7 @@ internal event EventHandler ContextRegained { using VoidSignal signal = new VoidSignal(Interop.StageSignal.ContextRegainedSignal(stageCPtr), false); signal.Ensure()?.Disconnect(stageContextRegainedEventCallbackDelegate); - stageContextRegainedEventCallbackDelegate = null; + ReleaseSafeCallback(ref stageContextRegainedEventCallbackDelegate); } } } @@ -807,7 +808,7 @@ internal event EventHandler SceneCreated { if (stageSceneCreatedEventHandler == null) { - stageSceneCreatedEventCallbackDelegate = OnSceneCreated; + CreateSafeCallback(OnSceneCreated, out stageSceneCreatedEventCallbackDelegate); using VoidSignal signal = new VoidSignal(Interop.StageSignal.SceneCreatedSignal(stageCPtr), false); signal.Ensure()?.Connect(stageSceneCreatedEventCallbackDelegate); } @@ -820,7 +821,7 @@ internal event EventHandler SceneCreated { using VoidSignal signal = new VoidSignal(Interop.StageSignal.SceneCreatedSignal(stageCPtr), false); signal.Ensure()?.Disconnect(stageSceneCreatedEventCallbackDelegate); - stageSceneCreatedEventCallbackDelegate = null; + ReleaseSafeCallback(ref stageSceneCreatedEventCallbackDelegate); } } } @@ -1751,7 +1752,7 @@ public event EventHandler VisibilityChanged { if (VisibilityChangedEventHandler == null) { - VisibilityChangedEventCallback = OnVisibilityChanged; + CreateSafeCallback(OnVisibilityChanged, out VisibilityChangedEventCallback); using WindowVisibilityChangedEvent signal = new WindowVisibilityChangedEvent(Interop.WindowVisibilityChangedSignal.GetSignal(Window.getCPtr(this)), false); signal.Ensure()?.Connect(VisibilityChangedEventCallback); } @@ -1764,7 +1765,7 @@ public event EventHandler VisibilityChanged { using WindowVisibilityChangedEvent signal = new WindowVisibilityChangedEvent(Interop.WindowVisibilityChangedSignal.GetSignal(Window.getCPtr(this)), false); signal.Ensure()?.Disconnect(VisibilityChangedEventCallback); - VisibilityChangedEventCallback = null; + ReleaseSafeCallback(ref VisibilityChangedEventCallback); } } } @@ -1824,7 +1825,7 @@ public event EventHandler AuxiliaryMessage { if (auxiliaryMessageEventHandler == null) { - auxiliaryMessageEventCallback = OnAuxiliaryMessage; + CreateSafeCallback(OnAuxiliaryMessage, out auxiliaryMessageEventCallback); using WindowAuxiliaryMessageSignal signal = new WindowAuxiliaryMessageSignal(Interop.WindowAuxiliaryMessageSignalType.Get(SwigCPtr), false); signal.Ensure()?.Connect(auxiliaryMessageEventCallback); } @@ -1837,7 +1838,7 @@ public event EventHandler AuxiliaryMessage { using WindowAuxiliaryMessageSignal signal = new WindowAuxiliaryMessageSignal(Interop.WindowAuxiliaryMessageSignalType.Get(SwigCPtr), false); signal.Ensure()?.Disconnect(auxiliaryMessageEventCallback); - auxiliaryMessageEventCallback = null; + ReleaseSafeCallback(ref auxiliaryMessageEventCallback); } } } @@ -1938,7 +1939,7 @@ public event EventHandler InsetsChanged { if (insetsChangedEventHandler == null) { - insetsChangedEventCallback = OnInsetsChanged; + CreateSafeCallback(OnInsetsChanged, out insetsChangedEventCallback); using WindowInsetsChangedSignal signal = new WindowInsetsChangedSignal(Interop.WindowInsetsChangedSignalType.Get(SwigCPtr), false); signal.Ensure()?.Connect(insetsChangedEventCallback); } @@ -1951,7 +1952,7 @@ public event EventHandler InsetsChanged { using WindowInsetsChangedSignal signal = new WindowInsetsChangedSignal(Interop.WindowInsetsChangedSignalType.Get(SwigCPtr), false); signal.Ensure()?.Disconnect(insetsChangedEventCallback); - insetsChangedEventCallback = null; + ReleaseSafeCallback(ref insetsChangedEventCallback); } } } @@ -2008,7 +2009,7 @@ public event EventHandler AccessibilityHighligh { if (AccessibilityHighlightEventHandler == null) { - AccessibilityHighlightEventCallback = OnAccessibilityHighlight; + CreateSafeCallback(OnAccessibilityHighlight, out AccessibilityHighlightEventCallback); using WindowAccessibilityHighlightEvent signal = new WindowAccessibilityHighlightEvent(Interop.WindowAccessibilityHighlightSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Connect(AccessibilityHighlightEventCallback); } @@ -2021,10 +2022,24 @@ public event EventHandler AccessibilityHighligh { using WindowAccessibilityHighlightEvent signal = new WindowAccessibilityHighlightEvent(Interop.WindowAccessibilityHighlightSignal.GetSignal(SwigCPtr), false); signal.Ensure()?.Disconnect(AccessibilityHighlightEventCallback); - AccessibilityHighlightEventCallback = null; + ReleaseSafeCallback(ref AccessibilityHighlightEventCallback); } } } + + void CreateSafeCallback(T method, out T safeCallback) where T : Delegate + { + AddToNativeHolder(method); + safeCallback = method; + } + + void ReleaseSafeCallback(ref T safeCallback) where T : Delegate + { + Debug.Assert(safeCallback != null); + RemoveFromNativeHolder(safeCallback); + safeCallback = null; + } + } /// From 2a277420ab02c85cd0bd50919bfc754b87d17f2d Mon Sep 17 00:00:00 2001 From: Jiyun Yang Date: Fri, 6 Dec 2024 13:10:11 +0900 Subject: [PATCH 3/3] Add guard for window callbacks to check disposal Signed-off-by: Jiyun Yang --- .../src/public/Window/WindowEvent.cs | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/src/Tizen.NUI/src/public/Window/WindowEvent.cs b/src/Tizen.NUI/src/public/Window/WindowEvent.cs index 3cdd9b5f482..f416a081c4d 100755 --- a/src/Tizen.NUI/src/public/Window/WindowEvent.cs +++ b/src/Tizen.NUI/src/public/Window/WindowEvent.cs @@ -1037,6 +1037,11 @@ internal void DisconnectNativeSignals() private void OnWindowFocusedChanged(IntPtr window, bool focusGained) { + if (IsDisposedOrQueued) + { + return; + } + if (window == IntPtr.Zero) { NUILog.Error("OnWindowFocusedChanged() Window is null! Do nothing!"); @@ -1053,6 +1058,12 @@ private void OnWindowFocusedChanged(IntPtr window, bool focusGained) private bool OnWindowTouch(IntPtr view, IntPtr touchData) { + if (IsDisposedOrQueued) + { + // Ignore native callback if the window is disposed or queued for disposal. + return false; + } + if (touchData == global::System.IntPtr.Zero) { NUILog.Error("touchData should not be null!"); @@ -1070,6 +1081,12 @@ private bool OnWindowTouch(IntPtr view, IntPtr touchData) private bool OnWindowInterceptTouch(IntPtr view, IntPtr touchData) { + if (IsDisposedOrQueued) + { + // Ignore native callback if the window is disposed or queued for disposal. + return false; + } + if (touchData == global::System.IntPtr.Zero) { NUILog.Error("touchData should not be null!"); @@ -1088,6 +1105,12 @@ private bool OnWindowInterceptTouch(IntPtr view, IntPtr touchData) private bool OnStageWheel(IntPtr rootLayer, IntPtr wheelEvent) { + if (IsDisposedOrQueued) + { + // Ignore native callback if the window is disposed or queued for disposal. + return false; + } + if (wheelEvent == global::System.IntPtr.Zero) { NUILog.Error("wheelEvent should not be null!"); @@ -1105,6 +1128,12 @@ private bool OnStageWheel(IntPtr rootLayer, IntPtr wheelEvent) private bool OnWindowInterceptWheel(IntPtr view, IntPtr wheelEvent) { + if (IsDisposedOrQueued) + { + // Ignore native callback if the window is disposed or queued for disposal. + return false; + } + if (wheelEvent == global::System.IntPtr.Zero) { NUILog.Error("wheelEvent should not be null!"); @@ -1124,6 +1153,12 @@ private bool OnWindowInterceptWheel(IntPtr view, IntPtr wheelEvent) // Callback for Stage KeyEventsignal private void OnStageKey(IntPtr data) { + if (IsDisposedOrQueued) + { + // Ignore native callback if the window is disposed or queued for disposal. + return; + } + if (stageKeyHandler != null) { KeyEventArgs e = new KeyEventArgs(); @@ -1136,6 +1171,12 @@ private void OnStageKey(IntPtr data) // Callback for Stage InterceptKeyEventsignal private bool OnStageInterceptKey(IntPtr data) { + if (IsDisposedOrQueued) + { + // Ignore native callback if the window is disposed or queued for disposal. + return false; + } + bool consumed = false; if (stageInterceptKeyHandler != null) { @@ -1150,29 +1191,54 @@ private bool OnStageInterceptKey(IntPtr data) // Callback for Stage EventProcessingFinishedSignal private void OnEventProcessingFinished() { + if (IsDisposedOrQueued) + { + return; + } + stageEventProcessingFinishedEventHandler?.Invoke(this, null); } // Callback for Stage ContextLostSignal private void OnContextLost() { + if (IsDisposedOrQueued) + { + return; + } + stageContextLostEventHandler?.Invoke(this, null); } // Callback for Stage ContextRegainedSignal private void OnContextRegained() { + if (IsDisposedOrQueued) + { + return; + } + stageContextRegainedEventHandler?.Invoke(this, null); } // Callback for Stage SceneCreatedSignal private void OnSceneCreated() { + if (IsDisposedOrQueued) + { + return; + } + stageSceneCreatedEventHandler?.Invoke(this, null); } private void OnResized(IntPtr window, IntPtr windowSize) { + if (IsDisposedOrQueued) + { + return; + } + if (window == IntPtr.Zero) { NUILog.Error("OnResized() Window is null! Do nothing!"); @@ -1196,6 +1262,11 @@ private void OnResized(IntPtr window, IntPtr windowSize) private void OnWindowFocusedChanged2(IntPtr window, bool focusGained) { + if (IsDisposedOrQueued) + { + return; + } + if (window == IntPtr.Zero) { NUILog.Error("OnWindowFocusedChanged() Window is null! Do nothing!"); @@ -1212,6 +1283,11 @@ private void OnWindowFocusedChanged2(IntPtr window, bool focusGained) private void OnTransitionEffect(IntPtr window, int state, int type) { + if (IsDisposedOrQueued) + { + return; + } + if (window == global::System.IntPtr.Zero) { return; @@ -1229,6 +1305,11 @@ private void OnTransitionEffect(IntPtr window, int state, int type) private void OnMoved(IntPtr window, IntPtr position) { + if (IsDisposedOrQueued) + { + return; + } + if (window == global::System.IntPtr.Zero) { return; @@ -1245,6 +1326,11 @@ private void OnMoved(IntPtr window, IntPtr position) private void OnOrientationChanged(IntPtr window, int orientation) { + if (IsDisposedOrQueued) + { + return; + } + if (window == global::System.IntPtr.Zero) { return; @@ -1261,12 +1347,23 @@ private void OnOrientationChanged(IntPtr window, int orientation) private void OnKeyboardRepeatSettingsChanged() { + if (IsDisposedOrQueued) + { + return; + } + keyboardRepeatSettingsChangedHandler?.Invoke(this, null); return; } private void OnWindowMouseInOutEvent(IntPtr view, IntPtr mouseEvent) { + if (IsDisposedOrQueued) + { + // Ignore native callback if the window is disposed or queued for disposal. + return; + } + if (mouseEvent == global::System.IntPtr.Zero) { NUILog.Error("mouseEvent should not be null!"); @@ -1283,6 +1380,11 @@ private void OnWindowMouseInOutEvent(IntPtr view, IntPtr mouseEvent) private void OnMoveCompleted(IntPtr window, IntPtr position) { + if (IsDisposedOrQueued) + { + return; + } + if (window == global::System.IntPtr.Zero) { return; @@ -1298,6 +1400,11 @@ private void OnMoveCompleted(IntPtr window, IntPtr position) private void OnResizeCompleted(IntPtr window, IntPtr size) { + if (IsDisposedOrQueued) + { + return; + } + if (window == global::System.IntPtr.Zero) { return; @@ -1313,6 +1420,12 @@ private void OnResizeCompleted(IntPtr window, IntPtr size) private void OnWindowMouseRelativeEvent(IntPtr view, IntPtr mouseEvent) { + if (IsDisposedOrQueued) + { + // Ignore native callback if the window is disposed or queued for disposal. + return; + } + if (mouseEvent == global::System.IntPtr.Zero) { NUILog.Error("mouseEvent should not be null!"); @@ -1329,6 +1442,12 @@ private void OnWindowMouseRelativeEvent(IntPtr view, IntPtr mouseEvent) private void OnWindowPointerConstraintsEvent(IntPtr view, IntPtr constraintsEvent) { + if (IsDisposedOrQueued) + { + // Ignore native callback if the window is disposed or queued for disposal. + return; + } + if (constraintsEvent == global::System.IntPtr.Zero) { NUILog.Error("constraintsEvent should not be null!"); @@ -1345,6 +1464,12 @@ private void OnWindowPointerConstraintsEvent(IntPtr view, IntPtr constraintsEven private bool OnWindowHover(IntPtr view, IntPtr hoverData) { + if (IsDisposedOrQueued) + { + // Ignore native callback if the window is disposed or queued for disposal. + return false; + } + if (hoverData == global::System.IntPtr.Zero) { NUILog.Error("hoverData should not be null!"); @@ -1689,6 +1814,12 @@ public EffectType Type private void OnDetentEvent(IntPtr wheelEvent) { + if (IsDisposedOrQueued) + { + // Ignore native callback if the window is disposed or queued for disposal. + return; + } + WheelEventArgs e = new WheelEventArgs(); if (wheelEvent != global::System.IntPtr.Zero) @@ -1722,6 +1853,11 @@ public bool Visibility private void OnVisibilityChanged(IntPtr window, bool visibility) { + if (IsDisposedOrQueued) + { + return; + } + if (window == global::System.IntPtr.Zero) { NUILog.Error("[ERR] OnVisibilityChanged() window is null"); @@ -1785,6 +1921,11 @@ public void VisibiltyChangedSignalEmit(bool visibility) private void OnAuxiliaryMessage(IntPtr kData, IntPtr vData, IntPtr optionsArray) { + if (IsDisposedOrQueued) + { + return; + } + if (kData == IntPtr.Zero || vData == IntPtr.Zero) { return; @@ -1918,6 +2059,11 @@ internal set private void OnInsetsChanged(int partType, int partState, IntPtr extents) { + if (IsDisposedOrQueued) + { + return; + } + if (insetsChangedEventHandler != null) { InsetsChangedEventArgs e = new InsetsChangedEventArgs(); @@ -1980,6 +2126,11 @@ public bool AccessibilityHighlight private void OnAccessibilityHighlight(IntPtr window, bool highlight) { + if (IsDisposedOrQueued) + { + return; + } + if (window == global::System.IntPtr.Zero) { NUILog.Error("[ERR] OnAccessibilityHighlight() window is null");