09e9f7b4c91a91529d70d8eedd8d00eebc7577a8
[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         /// <summary>
29         /// The flag to check if it is already disposed of.
30         /// </summary>
31         /// <since_tizen> 6 </since_tizen>
32         [Obsolete("Deprecated in API9, will be removed in API11, Use Disposed")]
33         [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "<Pending>")]
34         protected bool disposed = false;
35
36         private global::System.Runtime.InteropServices.HandleRef swigCPtr;
37         private bool swigCMemOwn { get; set; }
38         private bool isDisposeQueued = false;
39
40         /// <summary>
41         /// Create an instance of Disposable.
42         /// </summary>
43         /// <since_tizen> 6 </since_tizen>
44         public Disposable()
45         {
46             swigCMemOwn = false;
47             swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
48         }
49
50         /// This will not be public.
51         [EditorBrowsable(EditorBrowsableState.Never)]
52         public Disposable(global::System.IntPtr cPtr, bool cMemoryOwn)
53         {
54             swigCMemOwn = cMemoryOwn;
55             swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
56         }
57
58         /// <summary>
59         /// Dispose.
60         /// </summary>
61         /// <since_tizen> 6 </since_tizen>
62         ~Disposable() => Dispose(false);
63
64         /// <summary>
65         /// Dispose.
66         /// </summary>
67         /// <since_tizen> 6 </since_tizen>
68         public void Dispose()
69         {
70             if (isDisposeQueued)
71             {
72                 Dispose(DisposeTypes.Implicit);
73             }
74             else
75             {
76                 Dispose(true);
77             }
78             GC.SuppressFinalize(this);
79         }
80
81         internal static global::System.Runtime.InteropServices.HandleRef getCPtr(Disposable obj)
82         {
83             return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.SwigCPtr;
84         }
85
86         /// <summary>
87         /// Hidden API (Inhouse API).
88         /// Dispose. 
89         /// </summary>
90         /// <remarks>
91         /// Following the guide of https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose.
92         /// This will replace "protected virtual void Dispose(DisposeTypes type)" which is exactly same in functionality.
93         /// </remarks>
94         /// <param name="disposing">true in order to free managed objects</param>
95         // Protected implementation of Dispose pattern.
96         [EditorBrowsable(EditorBrowsableState.Never)]
97         protected virtual void Dispose(bool disposing)
98         {
99             if (disposed)
100             {
101                 return;
102             }
103
104             if (disposing)
105             {
106                 // TODO: dispose managed state (managed objects).
107                 // Explicit call. user calls Dispose()
108
109                 //Throw exception if Dispose() is called in separate thread.
110                 if (!Window.IsInstalled())
111                 {
112                     var process = global::System.Diagnostics.Process.GetCurrentProcess().Id;
113                     var thread = global::System.Threading.Thread.CurrentThread.ManagedThreadId;
114                     var me = this.GetType().FullName;
115
116                     Tizen.Log.Fatal("NUI", $"[NUI][Disposable]This API called from separate thread. This API must be called from MainThread. \n" +
117                         $" process:{process} thread:{thread}, disposing:{disposing}, isDisposed:{this.disposed}, isDisposeQueued:{this.isDisposeQueued}, me:{me}\n");
118
119                     //to fix ArtApp black screen issue. this will be enabled after talking with ArtApp team and fixing it.
120                     // throw new global::System.InvalidOperationException("[NUI][Disposable]This API called from separate thread. This API must be called from MainThread. \n" +
121                     //     $" process:{process} thread:{thread}, disposing:{disposing}, isDisposed:{this.disposed}, isDisposeQueued:{this.isDisposeQueued}, me:{me}\n");
122                 }
123
124                 if (isDisposeQueued)
125                 {
126                     Tizen.Log.Fatal("NUI", $"[Disposable]should not be here! (dead code) this will be removed!");
127
128                     //to fix ArtApp black screen issue. this will be enabled after talking with ArtApp team and fixing it.
129                     // throw new global::System.Exception($"[NUI] should not be here! (dead code) this will be removed!");
130                     Dispose(DisposeTypes.Implicit);
131                 }
132                 else
133                 {
134                     Dispose(DisposeTypes.Explicit);
135                 }
136             }
137             else
138             {
139                 // Implicit call. user doesn't call Dispose(), so this object is added into DisposeQueue to be disposed automatically.
140                 if (!isDisposeQueued)
141                 {
142                     isDisposeQueued = true;
143                     DisposeQueue.Instance.Add(this);
144                 }
145             }
146
147             // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
148             // TODO: set large fields to null.
149         }
150
151         /// <summary>
152         /// Dispose.
153         /// </summary>
154         /// <since_tizen> 6 </since_tizen>
155         protected virtual void Dispose(DisposeTypes type)
156         {
157             if (disposed)
158             {
159                 return;
160             }
161
162             if (type == DisposeTypes.Explicit)
163             {
164                 //Called by User
165                 //Release your own managed resources here.
166                 //You should release all of your own disposable objects here.
167             }
168
169             //Release your own unmanaged resources here.
170             //You should not access any managed member here except static instance.
171             //because the execution order of Finalizes is non-deterministic.
172             if (swigCPtr.Handle != global::System.IntPtr.Zero)
173             {
174                 if (SwigCMemOwn)
175                 {
176                     swigCMemOwn = false;
177                     ReleaseSwigCPtr(swigCPtr);
178                 }
179                 swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
180             }
181
182             disposed = true;
183         }
184
185         /// <summary>
186         /// Release swigCPtr.
187         /// </summary>
188         /// <since_tizen> 6 </since_tizen>
189         /// This will not be public opened.
190         [EditorBrowsable(EditorBrowsableState.Never)]
191         protected virtual void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
192         {
193         }
194
195         internal global::System.Runtime.InteropServices.HandleRef SwigCPtr
196         {
197             get => swigCPtr;
198             set
199             {
200                 swigCPtr = value;
201             }
202         }
203
204         internal bool SwigCMemOwn => swigCMemOwn;
205
206         /// <summary>
207         /// The flag to check if it is already disposed of.
208         /// </summary>
209         [EditorBrowsable(EditorBrowsableState.Never)]
210         protected internal bool Disposed => disposed;
211     }
212 }