[NUI] Clean up DisconnectFromSignals(). and Add Exception when Animation is used...
authordongsug.song <dongsug.song@samsung.com>
Thu, 16 Sep 2021 01:54:15 +0000 (10:54 +0900)
committerdongsug-song <35130733+dongsug-song@users.noreply.github.com>
Mon, 27 Sep 2021 08:27:23 +0000 (17:27 +0900)
- Add Exception when Animation's method or property is used after itself has been disposed already. (requested by GBM)
- All NUI object will throw an ObjectDisposedException when it is tried to be used after disposed.
- BaseHandle's internal SwigCPtr has setter and getter, but setter seems to be dangerous so it is changed to be getter only. (requested by GBM)
- SwigCPtr becomes only getter, so DisconnectFromSignals() has been changed accordingly.

src/Tizen.NUI/src/public/BaseComponents/Scrollable.cs
src/Tizen.NUI/src/public/BaseComponents/View.cs
src/Tizen.NUI/src/public/BaseComponents/ViewEvent.cs
src/Tizen.NUI/src/public/BaseComponents/ViewInternal.cs
src/Tizen.NUI/src/public/Common/BaseHandle.cs
test/Tizen.NUI.Samples/Tizen.NUI.Samples.sln
test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/DisposeWithoutEventUnsubscribedTest.cs [new file with mode: 0644]

index 92cf22f..8840356 100755 (executable)
@@ -539,30 +539,26 @@ namespace Tizen.NUI.BaseComponents
 
         private void DisConnectFromSignals()
         {
-            // Save current CPtr.
-            global::System.Runtime.InteropServices.HandleRef currentCPtr = SwigCPtr;
-
-            // Use BaseHandle CPtr as current might have been deleted already in derived classes.
-            SwigCPtr = GetBaseHandleCPtrHandleRef;
-
             if (scrollableCompletedCallbackDelegate != null)
             {
-                this.ScrollCompletedSignal().Disconnect(scrollableCompletedCallbackDelegate);
+                using ScrollableSignal signal = new ScrollableSignal(Interop.Scrollable.ScrollCompletedSignal(GetBaseHandleCPtrHandleRef), false);
+                signal?.Disconnect(scrollableCompletedCallbackDelegate);
+                scrollableCompletedCallbackDelegate = null;
             }
 
             if (scrollableUpdatedCallbackDelegate != null)
             {
-                this.ScrollUpdatedSignal().Disconnect(scrollableUpdatedCallbackDelegate);
+                using ScrollableSignal signal = new ScrollableSignal(Interop.Scrollable.ScrollUpdatedSignal(GetBaseHandleCPtrHandleRef), false);
+                signal?.Disconnect(scrollableUpdatedCallbackDelegate);
+                scrollableUpdatedCallbackDelegate = null;
             }
 
             if (scrollableStartedCallbackDelegate != null)
             {
-                this.ScrollStartedSignal().Disconnect(scrollableStartedCallbackDelegate);
+                using ScrollableSignal signal = new ScrollableSignal(Interop.Scrollable.ScrollStartedSignal(GetBaseHandleCPtrHandleRef), false);
+                signal?.Disconnect(scrollableStartedCallbackDelegate);
+                scrollableStartedCallbackDelegate = null;
             }
-
-            // BaseHandle CPtr is used in Registry and there is danger of deletion if we keep using it here.
-            // Restore current CPtr.
-            SwigCPtr = currentCPtr;
         }
 
         private void OnStarted(IntPtr vector2)
index 52e6ea8..7fbe58a 100755 (executable)
@@ -120,7 +120,8 @@ namespace Tizen.NUI.BaseComponents
             }
 
             onWindowSendEventCallback = SendViewAddedEventToWindow;
-            this.OnWindowSignal().Connect(onWindowSendEventCallback);
+            using ViewSignal signal = new ViewSignal(Interop.ActorSignal.ActorOnSceneSignal(SwigCPtr), false);
+            signal?.Connect(onWindowSendEventCallback);
 
             if (!shown)
             {
index e8773b7..dbb35d4 100755 (executable)
@@ -114,19 +114,23 @@ namespace Tizen.NUI.BaseComponents
                 if (keyInputFocusGainedEventHandler == null)
                 {
                     keyInputFocusGainedCallback = OnKeyInputFocusGained;
-                    this.KeyInputFocusGainedSignal().Connect(keyInputFocusGainedCallback);
+                    using KeyInputFocusSignal signal = new KeyInputFocusSignal(Interop.ViewSignal.KeyInputFocusGainedSignal(SwigCPtr), false);
+                    signal?.Connect(keyInputFocusGainedCallback);
                 }
-
                 keyInputFocusGainedEventHandler += value;
             }
 
             remove
             {
                 keyInputFocusGainedEventHandler -= value;
-
-                if (keyInputFocusGainedEventHandler == null && KeyInputFocusGainedSignal().Empty() == false)
+                if (keyInputFocusGainedEventHandler == null)
                 {
-                    this.KeyInputFocusGainedSignal().Disconnect(keyInputFocusGainedCallback);
+                    using KeyInputFocusSignal signal = new KeyInputFocusSignal(Interop.ViewSignal.KeyInputFocusGainedSignal(SwigCPtr), false);
+                    if (signal?.Empty() == false)
+                    {
+                        signal?.Disconnect(keyInputFocusGainedCallback);
+                        keyInputFocusGainedCallback = null;
+                    }
                 }
             }
         }
@@ -143,19 +147,23 @@ namespace Tizen.NUI.BaseComponents
                 if (keyInputFocusLostEventHandler == null)
                 {
                     keyInputFocusLostCallback = OnKeyInputFocusLost;
-                    this.KeyInputFocusLostSignal().Connect(keyInputFocusLostCallback);
+                    using KeyInputFocusSignal signal = new KeyInputFocusSignal(Interop.ViewSignal.KeyInputFocusLostSignal(SwigCPtr), false);
+                    signal?.Connect(keyInputFocusLostCallback);
                 }
-
                 keyInputFocusLostEventHandler += value;
             }
 
             remove
             {
                 keyInputFocusLostEventHandler -= value;
-
-                if (keyInputFocusLostEventHandler == null && KeyInputFocusLostSignal().Empty() == false)
+                if (keyInputFocusLostEventHandler == null)
                 {
-                    this.KeyInputFocusLostSignal().Disconnect(keyInputFocusLostCallback);
+                    using KeyInputFocusSignal signal = new KeyInputFocusSignal(Interop.ViewSignal.KeyInputFocusLostSignal(SwigCPtr), false);
+                    if (signal?.Empty() == false)
+                    {
+                        signal?.Disconnect(keyInputFocusLostCallback);
+                        keyInputFocusLostCallback = null;
+                    }
                 }
             }
         }
@@ -172,19 +180,23 @@ namespace Tizen.NUI.BaseComponents
                 if (keyEventHandler == null)
                 {
                     keyCallback = OnKeyEvent;
-                    this.KeyEventSignal().Connect(keyCallback);
+                    using ControlKeySignal signal = new ControlKeySignal(Interop.ViewSignal.KeyEventSignal(SwigCPtr), false);
+                    signal?.Connect(keyCallback);
                 }
-
                 keyEventHandler += value;
             }
 
             remove
             {
                 keyEventHandler -= value;
-
-                if (keyEventHandler == null && KeyEventSignal().Empty() == false)
+                if (keyEventHandler == null)
                 {
-                    this.KeyEventSignal().Disconnect(keyCallback);
+                    using ControlKeySignal signal = new ControlKeySignal(Interop.ViewSignal.KeyEventSignal(SwigCPtr), false);
+                    if (signal?.Empty() == false)
+                    {
+                        signal?.Disconnect(keyCallback);
+                        keyCallback = null;
+                    }
                 }
             }
         }
@@ -201,22 +213,24 @@ namespace Tizen.NUI.BaseComponents
                 if (onRelayoutEventHandler == null)
                 {
                     onRelayoutEventCallback = OnRelayout;
-                    this.OnRelayoutSignal().Connect(onRelayoutEventCallback);
+                    using ViewSignal signal = new ViewSignal(Interop.ActorSignal.ActorOnRelayoutSignal(SwigCPtr), false);
+                    signal?.Connect(onRelayoutEventCallback);
                 }
-
                 onRelayoutEventHandler += value;
             }
 
             remove
             {
                 onRelayoutEventHandler -= value;
-
-                if (onRelayoutEventHandler == null && OnRelayoutSignal().Empty() == false)
+                if (onRelayoutEventHandler == null)
                 {
-                    this.OnRelayoutSignal().Disconnect(onRelayoutEventCallback);
-                    onRelayoutEventCallback = null;
+                    using ViewSignal signal = new ViewSignal(Interop.ActorSignal.ActorOnRelayoutSignal(SwigCPtr), false);
+                    if (signal?.Empty() == false)
+                    {
+                        signal?.Disconnect(onRelayoutEventCallback);
+                        onRelayoutEventCallback = null;
+                    }
                 }
-
             }
         }
 
@@ -234,19 +248,23 @@ namespace Tizen.NUI.BaseComponents
                 if (interceptTouchDataEventHandler == null)
                 {
                     interceptTouchDataCallback = OnInterceptTouch;
-                    this.InterceptTouchSignal().Connect(interceptTouchDataCallback);
+                    using TouchDataSignal signal = new TouchDataSignal(Interop.ActorSignal.ActorInterceptTouchSignal(SwigCPtr), false);
+                    signal?.Connect(interceptTouchDataCallback);
                 }
-
                 interceptTouchDataEventHandler += value;
             }
 
             remove
             {
                 interceptTouchDataEventHandler -= value;
-
-                if (interceptTouchDataEventHandler == null && InterceptTouchSignal().Empty() == false)
+                if (interceptTouchDataEventHandler == null)
                 {
-                    this.InterceptTouchSignal().Disconnect(interceptTouchDataCallback);
+                    using TouchDataSignal signal = new TouchDataSignal(Interop.ActorSignal.ActorInterceptTouchSignal(SwigCPtr), false);
+                    if (signal?.Empty() == false)
+                    {
+                        signal?.Disconnect(interceptTouchDataCallback);
+                        interceptTouchDataCallback = null;
+                    }
                 }
             }
         }
@@ -276,19 +294,23 @@ namespace Tizen.NUI.BaseComponents
                 if (touchDataEventHandler == null)
                 {
                     touchDataCallback = OnTouch;
-                    this.TouchSignal().Connect(touchDataCallback);
+                    using TouchDataSignal signal = new TouchDataSignal(Interop.ActorSignal.ActorTouchSignal(SwigCPtr), false);
+                    signal.Connect(touchDataCallback);
                 }
-
                 touchDataEventHandler += value;
             }
 
             remove
             {
                 touchDataEventHandler -= value;
-
-                if (touchDataEventHandler == null && TouchSignal().Empty() == false)
+                if (touchDataEventHandler == null)
                 {
-                    this.TouchSignal().Disconnect(touchDataCallback);
+                    using TouchDataSignal signal = new TouchDataSignal(Interop.ActorSignal.ActorTouchSignal(SwigCPtr), false);
+                    if (signal.Empty() == false)
+                    {
+                        signal.Disconnect(touchDataCallback);
+                        touchDataCallback = null;
+                    }
                 }
             }
         }
@@ -305,21 +327,24 @@ namespace Tizen.NUI.BaseComponents
                 if (hoverEventHandler == null)
                 {
                     hoverEventCallback = OnHoverEvent;
-                    this.HoveredSignal().Connect(hoverEventCallback);
+                    using HoverSignal signal = new HoverSignal(Interop.ActorSignal.ActorHoveredSignal(SwigCPtr), false);
+                    signal?.Connect(hoverEventCallback);
                 }
-
                 hoverEventHandler += value;
             }
 
             remove
             {
                 hoverEventHandler -= value;
-
-                if (hoverEventHandler == null && HoveredSignal().Empty() == false)
+                if (hoverEventHandler == null)
                 {
-                    this.HoveredSignal().Disconnect(hoverEventCallback);
+                    using HoverSignal signal = new HoverSignal(Interop.ActorSignal.ActorHoveredSignal(SwigCPtr), false);
+                    if (signal?.Empty() == false)
+                    {
+                        signal?.Disconnect(hoverEventCallback);
+                        hoverEventCallback = null;
+                    }
                 }
-
             }
         }
 
@@ -335,7 +360,8 @@ namespace Tizen.NUI.BaseComponents
                 if (wheelEventHandler == null)
                 {
                     wheelEventCallback = OnWheelEvent;
-                    this.WheelEventSignal().Connect(wheelEventCallback);
+                    using WheelSignal signal = new WheelSignal(Interop.ActorSignal.ActorWheelEventSignal(SwigCPtr), false);
+                    signal?.Connect(wheelEventCallback);
                 }
                 wheelEventHandler += value;
 
@@ -349,9 +375,14 @@ namespace Tizen.NUI.BaseComponents
             remove
             {
                 wheelEventHandler -= value;
-                if (wheelEventHandler == null && WheelEventSignal().Empty() == false)
+                if (wheelEventHandler == null)
                 {
-                    this.WheelEventSignal().Disconnect(wheelEventCallback);
+                    using WheelSignal signal = new WheelSignal(Interop.ActorSignal.ActorWheelEventSignal(SwigCPtr), false);
+                    if (signal?.Empty() == false)
+                    {
+                        signal?.Disconnect(wheelEventCallback);
+                        wheelEventCallback = null;
+                    }
                 }
 
                 WindowWheelEventHandler -= value;
@@ -374,20 +405,23 @@ namespace Tizen.NUI.BaseComponents
                 if (onWindowEventHandler == null)
                 {
                     onWindowEventCallback = OnWindow;
-                    this.OnWindowSignal().Connect(onWindowEventCallback);
+                    using ViewSignal signal = new ViewSignal(Interop.ActorSignal.ActorOnSceneSignal(SwigCPtr), false);
+                    signal?.Connect(onWindowEventCallback);
                 }
-
                 onWindowEventHandler += value;
             }
 
             remove
             {
                 onWindowEventHandler -= value;
-
-                if (onWindowEventHandler == null && OnWindowSignal().Empty() == false)
+                if (onWindowEventHandler == null)
                 {
-                    this.OnWindowSignal().Disconnect(onWindowEventCallback);
-                    onWindowEventCallback = null;
+                    using ViewSignal signal = new ViewSignal(Interop.ActorSignal.ActorOnSceneSignal(SwigCPtr), false);
+                    if (signal?.Empty() == false)
+                    {
+                        signal?.Disconnect(onWindowEventCallback);
+                        onWindowEventCallback = null;
+                    }
                 }
             }
         }
@@ -404,20 +438,23 @@ namespace Tizen.NUI.BaseComponents
                 if (offWindowEventHandler == null)
                 {
                     offWindowEventCallback = OffWindow;
-                    this.OffWindowSignal().Connect(offWindowEventCallback);
+                    using ViewSignal signal = new ViewSignal(Interop.ActorSignal.ActorOffSceneSignal(SwigCPtr), false);
+                    signal?.Connect(offWindowEventCallback);
                 }
-
                 offWindowEventHandler += value;
             }
 
             remove
             {
                 offWindowEventHandler -= value;
-
-                if (offWindowEventHandler == null && OffWindowSignal().Empty() == false)
+                if (offWindowEventHandler == null)
                 {
-                    this.OffWindowSignal().Disconnect(offWindowEventCallback);
-                    offWindowEventCallback = null;
+                    using ViewSignal signal = new ViewSignal(Interop.ActorSignal.ActorOffSceneSignal(SwigCPtr), false);
+                    if (signal?.Empty() == false)
+                    {
+                        signal?.Disconnect(offWindowEventCallback);
+                        offWindowEventCallback = null;
+                    }
                 }
             }
         }
@@ -492,20 +529,23 @@ namespace Tizen.NUI.BaseComponents
                 if (resourcesLoadedEventHandler == null)
                 {
                     ResourcesLoadedCallback = OnResourcesLoaded;
-                    this.ResourcesLoadedSignal().Connect(ResourcesLoadedCallback);
+                    using ViewSignal signal = new ViewSignal(Interop.View.ResourceReadySignal(SwigCPtr), false);
+                    signal?.Connect(ResourcesLoadedCallback);
                 }
-
                 resourcesLoadedEventHandler += value;
             }
 
             remove
             {
                 resourcesLoadedEventHandler -= value;
-
-                if (resourcesLoadedEventHandler == null && ResourcesLoadedSignal().Empty() == false)
+                if (resourcesLoadedEventHandler == null)
                 {
-                    this.ResourcesLoadedSignal().Disconnect(ResourcesLoadedCallback);
-                    ResourcesLoadedCallback = null;
+                    using ViewSignal signal = new ViewSignal(Interop.View.ResourceReadySignal(SwigCPtr), false);
+                    if (signal?.Empty() == false)
+                    {
+                        signal?.Disconnect(ResourcesLoadedCallback);
+                        ResourcesLoadedCallback = null;
+                    }
                 }
             }
         }
@@ -549,19 +589,23 @@ namespace Tizen.NUI.BaseComponents
                 if (backgroundResourceLoadedEventHandler == null)
                 {
                     backgroundResourceLoadedCallback = OnBackgroundResourceLoaded;
-                    this.ResourcesLoadedSignal().Connect(backgroundResourceLoadedCallback);
+                    using ViewSignal signal = new ViewSignal(Interop.View.ResourceReadySignal(SwigCPtr), false);
+                    signal?.Connect(backgroundResourceLoadedCallback);
                 }
-
                 backgroundResourceLoadedEventHandler += value;
             }
+            
             remove
             {
                 backgroundResourceLoadedEventHandler -= value;
-
-                if (backgroundResourceLoadedEventHandler == null && ResourcesLoadedSignal().Empty() == false)
+                if (backgroundResourceLoadedEventHandler == null)
                 {
-                    this.ResourcesLoadedSignal().Disconnect(backgroundResourceLoadedCallback);
-                    backgroundResourceLoadedCallback = null;
+                    using ViewSignal signal = new ViewSignal(Interop.View.ResourceReadySignal(SwigCPtr), false);
+                    if (signal?.Empty() == false)
+                    {
+                        signal?.Disconnect(backgroundResourceLoadedCallback);
+                        backgroundResourceLoadedCallback = null;
+                    }
                 }
             }
         }
index 214a0c9..c6427c0 100755 (executable)
@@ -1146,16 +1146,11 @@ namespace Tizen.NUI.BaseComponents
             //You should not access any managed member here except static instance.
             //because the execution order of Finalizes is non-deterministic.
 
-            // equivalent to "if (this != null)". more clear to understand.
-            if (this.HasBody())
-            {
-                DisConnectFromSignals();
-
-                foreach (View view in Children)
-                {
-                    view.InternalParent = null;
-                }
+            DisConnectFromSignals();
 
+            foreach (View view in Children)
+            {
+                view.InternalParent = null;
             }
 
             base.Dispose(type);
@@ -1201,117 +1196,102 @@ namespace Tizen.NUI.BaseComponents
 
         private void DisConnectFromSignals()
         {
-            // Save current CPtr.
-            global::System.Runtime.InteropServices.HandleRef currentCPtr = SwigCPtr;
-
-            // Use BaseHandle CPtr as current might have been deleted already in derived classes.
-            SwigCPtr = GetBaseHandleCPtrHandleRef;
-
             if (onRelayoutEventCallback != null)
             {
-                ViewSignal signal = this.OnRelayoutSignal();
+                using ViewSignal signal = new ViewSignal(Interop.ActorSignal.ActorOnRelayoutSignal(GetBaseHandleCPtrHandleRef), false);
                 signal?.Disconnect(onRelayoutEventCallback);
-                signal?.Dispose();
                 onRelayoutEventCallback = null;
             }
 
             if (offWindowEventCallback != null)
             {
-                ViewSignal signal = this.OffWindowSignal();
+                using ViewSignal signal = new ViewSignal(Interop.ActorSignal.ActorOffSceneSignal(GetBaseHandleCPtrHandleRef), false);
                 signal?.Disconnect(offWindowEventCallback);
-                signal?.Dispose();
                 offWindowEventCallback = null;
             }
 
             if (onWindowEventCallback != null)
             {
-                ViewSignal signal = this.OnWindowSignal();
+                using ViewSignal signal = new ViewSignal(Interop.ActorSignal.ActorOnSceneSignal(GetBaseHandleCPtrHandleRef), false);
                 signal?.Disconnect(onWindowEventCallback);
-                signal?.Dispose();
                 onWindowEventCallback = null;
             }
 
             if (wheelEventCallback != null)
             {
-                WheelSignal signal = this.WheelEventSignal();
+                using WheelSignal signal = new WheelSignal(Interop.ActorSignal.ActorWheelEventSignal(GetBaseHandleCPtrHandleRef), false);
                 signal?.Disconnect(wheelEventCallback);
-                signal?.Dispose();
+                wheelEventCallback = null;
             }
 
             if (WindowWheelEventHandler != null)
             {
                 NUIApplication.GetDefaultWindow().WheelEvent -= OnWindowWheelEvent;
+                WindowWheelEventHandler = null;
             }
 
             if (hoverEventCallback != null)
             {
-                HoverSignal signal = this.HoveredSignal();
+                using HoverSignal signal = new HoverSignal(Interop.ActorSignal.ActorHoveredSignal(GetBaseHandleCPtrHandleRef), false);
                 signal?.Disconnect(hoverEventCallback);
-                signal?.Dispose();
+                hoverEventCallback = null;
             }
 
             if (interceptTouchDataCallback != null)
             {
-                TouchDataSignal signal = this.InterceptTouchSignal();
+                using TouchDataSignal signal = new TouchDataSignal(Interop.ActorSignal.ActorInterceptTouchSignal(GetBaseHandleCPtrHandleRef), false);
                 signal?.Disconnect(interceptTouchDataCallback);
-                signal?.Dispose();
+                interceptTouchDataCallback = null;
             }
 
             if (touchDataCallback != null)
             {
-                TouchDataSignal signal = this.TouchSignal();
+                using TouchDataSignal signal = new TouchDataSignal(Interop.ActorSignal.ActorTouchSignal(GetBaseHandleCPtrHandleRef), false);
                 signal?.Disconnect(touchDataCallback);
-                signal?.Dispose();
+                touchDataCallback = null;
             }
 
             if (ResourcesLoadedCallback != null)
             {
-                ViewSignal signal = this.ResourcesLoadedSignal();
+                using ViewSignal signal = new ViewSignal(Interop.View.ResourceReadySignal(GetBaseHandleCPtrHandleRef), false);
                 signal?.Disconnect(ResourcesLoadedCallback);
-                signal?.Dispose();
                 ResourcesLoadedCallback = null;
             }
 
             if (keyCallback != null)
             {
-                ControlKeySignal signal = this.KeyEventSignal();
+                using ControlKeySignal signal = new ControlKeySignal(Interop.ViewSignal.KeyEventSignal(GetBaseHandleCPtrHandleRef), false);
                 signal?.Disconnect(keyCallback);
-                signal?.Dispose();
+                keyCallback = null;
             }
 
             if (keyInputFocusLostCallback != null)
             {
-                KeyInputFocusSignal signal = this.KeyInputFocusLostSignal();
+                using KeyInputFocusSignal signal = new KeyInputFocusSignal(Interop.ViewSignal.KeyInputFocusLostSignal(GetBaseHandleCPtrHandleRef), false);
                 signal?.Disconnect(keyInputFocusLostCallback);
-                signal?.Dispose();
+                keyInputFocusLostCallback = null;
             }
 
             if (keyInputFocusGainedCallback != null)
             {
-                KeyInputFocusSignal signal = this.KeyInputFocusGainedSignal();
+                using KeyInputFocusSignal signal = new KeyInputFocusSignal(Interop.ViewSignal.KeyInputFocusGainedSignal(GetBaseHandleCPtrHandleRef), false);
                 signal?.Disconnect(keyInputFocusGainedCallback);
-                signal?.Dispose();
+                keyInputFocusGainedCallback = null;
             }
 
             if (backgroundResourceLoadedCallback != null)
             {
-                ViewSignal signal = this.ResourcesLoadedSignal();
+                using ViewSignal signal = new ViewSignal(Interop.View.ResourceReadySignal(GetBaseHandleCPtrHandleRef), false);
                 signal?.Disconnect(backgroundResourceLoadedCallback);
-                signal?.Dispose();
                 backgroundResourceLoadedCallback = null;
             }
 
             if (onWindowSendEventCallback != null)
             {
-                ViewSignal signal = this.OnWindowSignal();
+                using ViewSignal signal = new ViewSignal(Interop.ActorSignal.ActorOnSceneSignal(GetBaseHandleCPtrHandleRef), false);
                 signal?.Disconnect(onWindowSendEventCallback);
-                signal?.Dispose();
                 onWindowSendEventCallback = null;
             }
-
-            // BaseHandle CPtr is used in Registry and there is danger of deletion if we keep using it here.
-            // Restore current CPtr.
-            SwigCPtr = currentCPtr;
         }
 
         /// <summary>
index ab48757..c0eb891 100644 (file)
@@ -566,10 +566,13 @@ namespace Tizen.NUI
 
         internal global::System.Runtime.InteropServices.HandleRef SwigCPtr
         {
-            get => swigCPtr;
-            set
+            get
             {
-                swigCPtr = value;
+                if (swigCPtr.Handle == IntPtr.Zero)
+                {
+                    throw new ObjectDisposedException(nameof(SwigCPtr), "Error! NUI's native dali object is already disposed. OR the native dali object handle of NUI becomes null!");
+                }
+                return swigCPtr;
             }
         }
 
index fff9ac0..09ee2be 100755 (executable)
@@ -35,6 +35,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Multimedia.Camera", "
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Applications.ThemeManager", "..\..\src\Tizen.Applications.ThemeManager\Tizen.Applications.ThemeManager.csproj", "{FB8B42D6-76CC-4836-8A80-58A816C6A17F}"
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.NUI.Extension", "..\..\src\Tizen.NUI.Extension\Tizen.NUI.Extension.csproj", "{47829CA1-0E21-4687-9ABB-0C27E1A67E85}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug|Any CPU = Debug|Any CPU
@@ -105,6 +107,10 @@ Global
                {FB8B42D6-76CC-4836-8A80-58A816C6A17F}.Debug|Any CPU.Build.0 = Debug|Any CPU
                {FB8B42D6-76CC-4836-8A80-58A816C6A17F}.Release|Any CPU.ActiveCfg = Release|Any CPU
                {FB8B42D6-76CC-4836-8A80-58A816C6A17F}.Release|Any CPU.Build.0 = Release|Any CPU
+               {47829CA1-0E21-4687-9ABB-0C27E1A67E85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {47829CA1-0E21-4687-9ABB-0C27E1A67E85}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {47829CA1-0E21-4687-9ABB-0C27E1A67E85}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {47829CA1-0E21-4687-9ABB-0C27E1A67E85}.Release|Any CPU.Build.0 = Release|Any CPU
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
diff --git a/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/DisposeWithoutEventUnsubscribedTest.cs b/test/Tizen.NUI.Samples/Tizen.NUI.Samples/Samples/DisposeWithoutEventUnsubscribedTest.cs
new file mode 100644 (file)
index 0000000..70668b7
--- /dev/null
@@ -0,0 +1,293 @@
+
+using global::System;
+using Tizen.NUI.BaseComponents;
+using System.Collections.Generic;
+
+namespace Tizen.NUI.Samples
+{
+    using tlog = Tizen.Log;
+    public class DisposeWithoutEventUnsubscribedTestAndAnimationDisposeTest : IExample
+    {
+        private const string tag = "NUITEST";
+        private const int NUMBER_OF_VIEW = 1000;
+        private const int INTERVAL_MS = 1000;
+        private const int MIN_POSITION = 100;
+        private const int MAX_POSITION = 900;
+        private const bool TURN_ON_GC = true;
+
+        private Window win;
+        private View rootView;
+        private int cnt;
+        private List<View> list = new List<View>();
+        private Random rand = new Random();
+        private bool toggle, toggleRemoveMany;
+        private string res;
+        private Timer timer;
+
+        public void Activate()
+        {
+            DisposeWithoutUnsubscribedEventTest();
+            AnimationDisposeTest();
+        }
+        public void Deactivate()
+        {
+            DisposeManyObject();
+            timer.Stop();
+            timer.Dispose();
+            rootView.Unparent();
+            rootView.Dispose();
+        }
+
+        private void AnimationDisposeTest()
+        {
+            var ani = new Animation(1000);
+            ani.AnimateTo(rootView, "size", new Size(500, 500, 0));
+            ani.Dispose();
+            try
+            {
+                ani.Play();
+                tlog.Fatal(tag, "this should not be shown! test NG!");
+            }
+            catch (Exception e)
+            {
+                if (e is ObjectDisposedException)
+                {
+                    tlog.Fatal(tag, "Animation is used after disposed! test OK!");
+                }
+                else
+                {
+                    tlog.Fatal(tag, $"unwanted exception came! test NG! exception:{e} msg:{e.Message}");
+                }
+            }
+
+            try
+            {
+                ani.Clear();
+                tlog.Fatal(tag, "this should not be shown! test NG!");
+            }
+            catch (Exception e)
+            {
+                if (e is ObjectDisposedException)
+                {
+                    tlog.Fatal(tag, "Animation is used after disposed! test OK!");
+                }
+                else
+                {
+                    tlog.Fatal(tag, $"unwanted exception came! test NG! exception:{e} msg:{e.Message}");
+                }
+            }
+        }
+
+        private void DisposeWithoutUnsubscribedEventTest()
+        {
+            win = NUIApplication.GetDefaultWindow();
+
+            res = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
+
+            rootView = new View()
+            {
+                Size = new Size(100, 100),
+                BackgroundColor = Color.Blue,
+            };
+            rootView.Relayout += View_Relayout;
+            win.Add(rootView);
+
+            timer = new Timer(INTERVAL_MS);
+            timer.Tick += Timer_Tick;
+            timer.Start();
+        }
+
+        private void AddManyObject()
+        {
+            tlog.Fatal(tag, $"AddManyObject()");
+
+            for (int i = 0; i < NUMBER_OF_VIEW; i++)
+            {
+                var child = new ImageView()
+                {
+                    ResourceUrl = res + "images/Dali/DaliDemo/application-icon-1.png",
+                    Size = new Size(60, 60),
+                    Position = new Position(rand.Next(MIN_POSITION, MAX_POSITION), rand.Next(MIN_POSITION, MAX_POSITION)),
+                    BackgroundColor = new Color((float)rand.NextDouble(), (float)rand.NextDouble(), (float)rand.NextDouble(), 1),
+                };
+
+                rootView.Add(child);
+                child.Relayout += Child_Relayout;
+                child.RemovedFromWindow += Child_RemovedFromWindow;
+                child.AddedToWindow += Child_AddedToWindow;
+                child.WheelEvent += Child_WheelEvent;
+                child.HoverEvent += Child_HoverEvent;
+                child.InterceptTouchEvent += Child_InterceptTouchEvent;
+                child.TouchEvent += Child_TouchEvent;
+                child.ResourcesLoaded += Child_ResourcesLoaded;
+                child.KeyEvent += Child_KeyEvent;
+                child.FocusLost += Child_FocusLost;
+                child.FocusGained += Child_FocusGained;
+            }
+        }
+
+        private void Child_FocusGained(object sender, EventArgs e)
+        {
+            if (++cnt % (NUMBER_OF_VIEW * 3) == 1)
+            {
+                tlog.Fatal(tag, $"Child_FocusGained() called!");
+            }
+        }
+
+        private void Child_FocusLost(object sender, EventArgs e)
+        {
+            if (++cnt % (NUMBER_OF_VIEW * 3) == 1)
+            {
+                tlog.Fatal(tag, $"Child_FocusLost() called!");
+            }
+        }
+
+        private bool Child_KeyEvent(object source, View.KeyEventArgs e)
+        {
+            if (++cnt % (NUMBER_OF_VIEW * 3) == 1)
+            {
+                tlog.Fatal(tag, $"Child_KeyEvent() called!");
+            }
+            return true;
+        }
+
+        private void Child_ResourcesLoaded(object sender, EventArgs e)
+        {
+            if (++cnt % (NUMBER_OF_VIEW * 3) == 1)
+            {
+                tlog.Fatal(tag, $"Child_ResourcesLoaded() called!");
+            }
+        }
+
+        private bool Child_TouchEvent(object source, View.TouchEventArgs e)
+        {
+            if (++cnt % (NUMBER_OF_VIEW * 3) == 1)
+            {
+                tlog.Fatal(tag, $"Child_TouchEvent() called!");
+            }
+            return true;
+        }
+
+        private bool Child_InterceptTouchEvent(object source, View.TouchEventArgs e)
+        {
+            if (++cnt % (NUMBER_OF_VIEW * 3) == 1)
+            {
+                tlog.Fatal(tag, $"Child_InterceptTouchEvent() called!");
+            }
+            return true;
+        }
+
+        private bool Child_HoverEvent(object source, View.HoverEventArgs e)
+        {
+            if (++cnt % (NUMBER_OF_VIEW * 3) == 1)
+            {
+                tlog.Fatal(tag, $"Child_HoverEvent() called!");
+            }
+            return true;
+        }
+
+        private bool Child_WheelEvent(object source, View.WheelEventArgs e)
+        {
+            if (++cnt % (NUMBER_OF_VIEW * 3) == 1)
+            {
+                tlog.Fatal(tag, $"Child_WheelEvent() called!");
+            }
+            return true;
+        }
+
+        private void Child_AddedToWindow(object sender, EventArgs e)
+        {
+            if (++cnt % (NUMBER_OF_VIEW * 3) == 1)
+            {
+                tlog.Fatal(tag, $"Child_AddedToWindow() called!");
+            }
+        }
+
+        private void Child_RemovedFromWindow(object sender, EventArgs e)
+        {
+            if (++cnt % (NUMBER_OF_VIEW * 3) == 1)
+            {
+                tlog.Fatal(tag, $"Child_RemovedFromWindow() called!");
+            }
+        }
+
+        private void Child_Relayout(object sender, EventArgs e)
+        {
+            if (++cnt % (NUMBER_OF_VIEW * 3) == 1)
+            {
+                tlog.Fatal(tag, $"Child_Relayout() called!");
+            }
+        }
+
+        private void View_Relayout(object sender, EventArgs e)
+        {
+            if (++cnt % (NUMBER_OF_VIEW * 3) == 1)
+            {
+                tlog.Fatal(tag, $"View_Relayout() called! cnt:{cnt}");
+            }
+        }
+
+        private void RemoveManyObject()
+        {
+            int childCnt = (int)rootView.ChildCount;
+            tlog.Fatal(tag, $"RemoveManyObject() child count:{childCnt}");
+
+            for (int i = childCnt - 1; i >= 0; i--)
+            {
+                var child = rootView.GetChildAt((uint)i);
+                rootView.Remove(child);
+            }
+        }
+        private void DisposeManyObject()
+        {
+            int childCnt = (int)rootView.ChildCount;
+            tlog.Fatal(tag, $"DisposeManyObject() child count:{childCnt}");
+
+            for (int i = childCnt - 1; i >= 0; i--)
+            {
+                var child = rootView.GetChildAt((uint)i);
+                rootView.Remove(child);
+                child.Size += new Size(100, 100);
+                child.Size -= new Size(100, 100);
+                child.Size += new Size(100, 100);
+                child.Size -= new Size(100, 100);
+                child.Dispose();
+            }
+        }
+
+        private bool Timer_Tick(object source, Timer.TickEventArgs e)
+        {
+            toggle = !toggle;
+            if (toggle)
+            {
+                AddManyObject();
+            }
+            else
+            {
+                toggleRemoveMany = !toggleRemoveMany;
+                if (toggleRemoveMany)
+                {
+                    RemoveManyObject();
+                }
+                else
+                {
+                    DisposeManyObject();
+                }
+            }
+
+            if (TURN_ON_GC)
+            {
+                FullGC();
+            }
+            return true;
+        }
+
+        private void FullGC()
+        {
+            global::System.GC.Collect();
+            global::System.GC.WaitForPendingFinalizers();
+            global::System.GC.Collect();
+        }
+
+    }
+}