[NUI] Fix WeakEvent bugs
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Common / Disposable.cs
1 /*
2  * Copyright(c) 2019 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 using System;
18 using System.ComponentModel;
19
20 namespace Tizen.NUI
21 {
22     /// <summary>
23     /// Disposable class.
24     /// </summary>
25     /// <since_tizen> 6 </since_tizen>
26     public class Disposable : global::System.IDisposable
27     {
28         static internal void Preload()
29         {
30             // Do nothing. Just call for load static values.
31         }
32
33         /// <summary>
34         /// The flag to check if it is already disposed of.
35         /// </summary>
36         /// <since_tizen> 6 </since_tizen>
37         [Obsolete("Deprecated in API9, will be removed in API11, Use Disposed")]
38         [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "<Pending>")]
39         protected bool disposed = false;
40
41         private global::System.Runtime.InteropServices.HandleRef swigCPtr;
42         private bool swigCMemOwn { get; set; }
43         private bool isDisposeQueued = false;
44
45         /// <summary>
46         /// Create an instance of Disposable.
47         /// </summary>
48         /// <since_tizen> 6 </since_tizen>
49         public Disposable()
50         {
51             swigCMemOwn = false;
52             swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
53         }
54
55         /// This will not be public.
56         [EditorBrowsable(EditorBrowsableState.Never)]
57         public Disposable(global::System.IntPtr cPtr, bool cMemoryOwn)
58         {
59             swigCMemOwn = cMemoryOwn;
60             swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
61         }
62
63         /// <summary>
64         /// Dispose.
65         /// </summary>
66         /// <since_tizen> 6 </since_tizen>
67         ~Disposable() => Dispose(false);
68
69         /// <summary>
70         /// Dispose.
71         /// </summary>
72         /// <since_tizen> 6 </since_tizen>
73         public void Dispose()
74         {
75             if (isDisposeQueued)
76             {
77                 Dispose(DisposeTypes.Implicit);
78             }
79             else
80             {
81                 Dispose(true);
82             }
83             GC.SuppressFinalize(this);
84         }
85
86         internal static global::System.Runtime.InteropServices.HandleRef getCPtr(Disposable obj)
87         {
88             return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.SwigCPtr;
89         }
90
91         /// <summary>
92         /// Hidden API (Inhouse API).
93         /// Dispose. 
94         /// </summary>
95         /// <remarks>
96         /// Following the guide of https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose.
97         /// This will replace "protected virtual void Dispose(DisposeTypes type)" which is exactly same in functionality.
98         /// </remarks>
99         /// <param name="disposing">true in order to free managed objects</param>
100         // Protected implementation of Dispose pattern.
101         [EditorBrowsable(EditorBrowsableState.Never)]
102         protected virtual void Dispose(bool disposing)
103         {
104             if (disposed)
105             {
106                 return;
107             }
108
109             if (disposing)
110             {
111                 // TODO: dispose managed state (managed objects).
112                 // Explicit call. user calls Dispose()
113
114                 if (isDisposeQueued)
115                 {
116                     Tizen.Log.Fatal("NUI", $"[Disposable]should not be here! (dead code) this will be removed!");
117
118                     //to fix ArtApp black screen issue. this will be enabled after talking with ArtApp team and fixing it.
119                     // throw new global::System.Exception($"[NUI] should not be here! (dead code) this will be removed!");
120                     Dispose(DisposeTypes.Implicit);
121                 }
122                 else
123                 {
124                     Dispose(DisposeTypes.Explicit);
125                 }
126             }
127             else
128             {
129                 // Implicit call. user doesn't call Dispose(), so this object is added into DisposeQueue to be disposed automatically.
130                 if (!isDisposeQueued)
131                 {
132                     isDisposeQueued = true;
133                     DisposeQueue.Instance.Add(this);
134                 }
135             }
136
137             // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
138             // TODO: set large fields to null.
139         }
140
141         /// <summary>
142         /// Dispose.
143         /// </summary>
144         /// <since_tizen> 6 </since_tizen>
145         protected virtual void Dispose(DisposeTypes type)
146         {
147             if (disposed)
148             {
149                 return;
150             }
151
152             if (type == DisposeTypes.Explicit)
153             {
154                 //Called by User
155                 //Release your own managed resources here.
156                 //You should release all of your own disposable objects here.
157             }
158
159             //Release your own unmanaged resources here.
160             //You should not access any managed member here except static instance.
161             //because the execution order of Finalizes is non-deterministic.
162             if (swigCPtr.Handle != global::System.IntPtr.Zero)
163             {
164                 var nativeSwigCPtr = swigCPtr.Handle;
165                 swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
166                 if (swigCMemOwn)
167                 {
168                     swigCMemOwn = false;
169                     ReleaseSwigCPtr(new global::System.Runtime.InteropServices.HandleRef(this, nativeSwigCPtr));
170                 }
171             }
172
173             disposed = true;
174         }
175
176         /// <summary>
177         /// Release swigCPtr.
178         /// </summary>
179         /// <since_tizen> 6 </since_tizen>
180         /// This will not be public opened.
181         [EditorBrowsable(EditorBrowsableState.Never)]
182         protected virtual void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
183         {
184         }
185
186         internal global::System.Runtime.InteropServices.HandleRef SwigCPtr
187         {
188             get => swigCPtr;
189             set
190             {
191                 swigCPtr = value;
192             }
193         }
194
195         internal bool SwigCMemOwn => swigCMemOwn;
196
197         /// <summary>
198         /// The flag to check if it is already disposed of.
199         /// </summary>
200         [EditorBrowsable(EditorBrowsableState.Never)]
201         protected internal bool Disposed => disposed;
202
203         /// <summary>
204         /// The flag to check if it is disposed by DisposeQueue.
205         /// </summary>
206         [EditorBrowsable(EditorBrowsableState.Never)]
207         protected internal bool IsDisposeQueued => isDisposeQueued;
208     }
209
210     internal static class DisposableExtension
211     {
212         internal static T Ensure<T>(this T caller) where T : Disposable
213         {
214             return (caller.SwigCPtr.Handle == System.IntPtr.Zero ? null : caller);
215         }
216     }
217 }