Let registry throw exception at error case
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Common / BaseHandle.cs
1 /*
2  * Copyright(c) 2022 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 using System.Runtime.CompilerServices;
20 using Tizen.NUI.Binding;
21 using global::System.Diagnostics;
22
23 namespace Tizen.NUI
24 {
25     /// <summary>
26     /// BaseHandle is a handle to an internal Dali resource.
27     /// </summary>
28     /// <since_tizen> 3 </since_tizen>
29     public class BaseHandle : Element, global::System.IDisposable
30     {
31         /// <summary>
32         /// swigCMemOwn
33         /// </summary>
34         /// <since_tizen> 3 </since_tizen>
35         [Obsolete("Deprecated in API9, will be removed in API11, Use SwigCMemOwn")]
36         [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "<Pending>")]
37         protected bool swigCMemOwn;
38
39         /// <summary>
40         /// The flag to check if it is already disposed of.
41         /// </summary>
42         /// <since_tizen> 3 </since_tizen>
43         [Obsolete("Deprecated in API9, will be removed in API11, Use Disposed")]
44         [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1051:Do not declare visible instance fields", Justification = "<Pending>")]
45         protected bool disposed = false;
46
47         private global::System.Runtime.InteropServices.HandleRef swigCPtr;
48         private bool registerMe;
49
50         //The flag to check who called Dispose(). (By User or DisposeQueue)
51         private bool isDisposeQueued = false;
52
53         /// <summary>
54         /// Create an instance of BaseHandle.
55         /// </summary>
56         /// <since_tizen> 3 </since_tizen>
57         public BaseHandle() : this(Interop.BaseHandle.NewBaseHandle())
58         {
59             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
60         }
61
62         /// <summary>
63         /// Create an instance of BaseHandle.
64         /// </summary>
65         /// <param name="handle">The BaseHandle instance.</param>
66         /// <since_tizen> 3 </since_tizen>
67         public BaseHandle(BaseHandle handle) : this(Interop.BaseHandle.NewBaseHandle(BaseHandle.getCPtr(handle)))
68         {
69             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
70         }
71
72         internal BaseHandle(global::System.IntPtr cPtr, bool cMemoryOwn)
73         {
74             //to catch derived classes dali native exceptions
75             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
76
77             DebugFileLogging.Instance.WriteLog($"BaseHandle.contructor with cMemeryOwn:{cMemoryOwn} START");
78
79             registerMe = swigCMemOwn = cMemoryOwn;
80             swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
81             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
82
83             if (registerMe)
84             {
85                 // Register this instance of BaseHandle in the registry.
86                 Registry.Register(this);
87             }
88
89             disposeDebuggingCtor();
90             DebugFileLogging.Instance.WriteLog($" BaseHandle.contructor with cMemeryOwn END");
91             DebugFileLogging.Instance.WriteLog($"=============================");
92         }
93
94         internal BaseHandle(global::System.IntPtr cPtr)
95         {
96             DebugFileLogging.Instance.WriteLog($"BaseHandle.contructor START");
97
98             registerMe = swigCMemOwn = true;
99
100             swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
101             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
102
103             if (registerMe)
104             {
105                 // Register this instance of BaseHandle in the registry.
106                 Registry.Register(this);
107             }
108
109             disposeDebuggingCtor();
110             DebugFileLogging.Instance.WriteLog($"BaseHandle.contructor END");
111             DebugFileLogging.Instance.WriteLog($"=============================");
112         }
113
114         /// <summary>
115         /// Dispose.
116         /// </summary>
117         /// <since_tizen> 3 </since_tizen>
118         // following this guide: https://docs.microsoft.com/ko-kr/dotnet/fundamentals/code-analysis/quality-rules/ca1063?view=vs-2019 (CA1063)
119         ~BaseHandle() => Dispose(false);
120
121         /// <summary>
122         /// Event when a property is set.
123         /// </summary>
124         /// <since_tizen> 5 </since_tizen>
125         /// <seealso cref="BindableObject.PropertyChanged"/>
126         [Obsolete("Deprecated in API9, will be removed in API11, Use BindableObject.PropertyChanged instead.")]
127         public event PropertyChangedEventHandler PropertySet;
128
129         internal global::System.Runtime.InteropServices.HandleRef GetBaseHandleCPtrHandleRef
130         {
131             get
132             {
133                 return swigCPtr;
134             }
135         }
136
137         /// <summary>
138         /// Returns the bool value true to indicate that an operand is true and returns false otherwise.
139         /// </summary>
140         /// <since_tizen> 3 </since_tizen>
141         public static bool operator true(BaseHandle handle)
142         {
143             // if the C# object is null, return false
144             if (BaseHandle.ReferenceEquals(handle, null))
145             {
146                 return false;
147             }
148             // returns true if the handle has a body, false otherwise
149             return handle.HasBody();
150         }
151
152         /// <summary>
153         /// Returns the bool false  to indicate that an operand is false and returns true otherwise.
154         /// </summary>
155         /// <since_tizen> 3 </since_tizen>
156         public static bool operator false(BaseHandle handle)
157         {
158             // if the C# object is null, return true
159             if (BaseHandle.ReferenceEquals(handle, null))
160             {
161                 return true;
162             }
163             return !handle.HasBody();
164         }
165
166         /// <summary>
167         /// Explicit conversion from Handle to bool.
168         /// </summary>
169         /// <since_tizen> 3 </since_tizen>
170         public static explicit operator bool(BaseHandle handle)
171         {
172             // if the C# object is null, return false
173             if (BaseHandle.ReferenceEquals(handle, null))
174             {
175                 return false;
176             }
177             // returns true if the handle has a body, false otherwise
178             return handle.HasBody();
179         }
180
181         /// <summary>
182         /// Equality operator
183         /// </summary>
184         /// <since_tizen> 3 </since_tizen>
185         public static bool operator ==(BaseHandle x, BaseHandle y)
186         {
187             // if the C# objects are the same return true
188             if (BaseHandle.ReferenceEquals(x, y))
189             {
190                 return true;
191             }
192             if (!BaseHandle.ReferenceEquals(x, null) && !BaseHandle.ReferenceEquals(y, null))
193             {
194                 // drop into native code to see if both handles point to the same body
195                 return x.IsEqual(y);
196             }
197
198             if (BaseHandle.ReferenceEquals(x, null) && !BaseHandle.ReferenceEquals(y, null))
199             {
200                 if (y.HasBody()) return false;
201                 else return true;
202             }
203             if (!BaseHandle.ReferenceEquals(x, null) && BaseHandle.ReferenceEquals(y, null))
204             {
205                 if (x.HasBody()) return false;
206                 else return true;
207             }
208
209             return false;
210         }
211
212         /// <summary>
213         /// Inequality operator. Returns Null if either operand is Null
214         /// </summary>
215         /// <since_tizen> 3 </since_tizen>
216         public static bool operator !=(BaseHandle x, BaseHandle y)
217         {
218             return !(x == y);
219         }
220
221         /// <summary>
222         /// Logical AND operator.<br />
223         /// It's possible when doing a  operator this function (opBitwiseAnd) is never called due to short circuiting.<br />
224         /// </summary>
225         /// <since_tizen> 3 </since_tizen>
226         public static BaseHandle operator &(BaseHandle x, BaseHandle y)
227         {
228             if (x == y)
229             {
230                 return x;
231             }
232             return null;
233         }
234
235         /// <summary>
236         /// Logical OR operator for ||.<br />
237         /// It's possible when doing a || this function (opBitwiseOr) is never called due to short circuiting.<br />
238         /// </summary>
239         /// <since_tizen> 3 </since_tizen>
240         public static BaseHandle operator |(BaseHandle x, BaseHandle y)
241         {
242             if (!BaseHandle.ReferenceEquals(x, null) || !BaseHandle.ReferenceEquals(y, null))
243             {
244                 if (x != null && x.HasBody())
245                 {
246                     return x;
247                 }
248                 if (y != null && y.HasBody())
249                 {
250                     return y;
251                 }
252                 return null;
253             }
254             return null;
255         }
256
257         /// <summary>
258         /// Logical ! operator
259         /// </summary>
260         /// <since_tizen> 3 </since_tizen>
261         public static bool operator !(BaseHandle x)
262         {
263             // if the C# object is null, return true
264             if (BaseHandle.ReferenceEquals(x, null))
265             {
266                 return true;
267             }
268             if (x.HasBody())
269             {
270                 return false;
271             }
272             return true;
273         }
274
275         /// <summary>
276         /// Equals
277         /// </summary>
278         /// <param name="o">The object should be compared.</param>
279         /// <returns>True if equal.</returns>
280         /// <since_tizen> 5 </since_tizen>
281         public override bool Equals(object o)
282         {
283             return base.Equals(o);
284         }
285
286         /// <summary>
287         /// Gets the hash code of this baseHandle.
288         /// </summary>
289         /// <returns>The hash code.</returns>
290         /// <since_tizen> 5 </since_tizen>
291         public override int GetHashCode()
292         {
293             return base.GetHashCode();
294         }
295
296         /// <summary>
297         /// Dispose.
298         /// </summary>
299         /// <since_tizen> 3 </since_tizen>
300         public void Dispose()
301         {
302             if (isDisposeQueued)
303             {
304                 Dispose(DisposeTypes.Implicit);
305             }
306             else
307             {
308                 Dispose(true);
309             }
310             GC.SuppressFinalize(this);
311         }
312
313         /// <summary>
314         /// Hidden API (Inhouse API).
315         /// Dispose. 
316         /// </summary>
317         /// <remarks>
318         /// Following the guide of https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose.
319         /// This will replace "protected virtual void Dispose(DisposeTypes type)" which is exactly same in functionality.
320         /// </remarks>
321         /// <param name="disposing">true in order to free managed objects</param>
322         // Protected implementation of Dispose pattern.
323         [EditorBrowsable(EditorBrowsableState.Never)]
324         protected virtual void Dispose(bool disposing)
325         {
326             if (disposed)
327             {
328                 return;
329             }
330
331             if (disposing)
332             {
333                 // TODO: dispose managed state (managed objects).
334                 // Explicit call. user calls Dispose()
335
336                 //Throw exception if Dispose() is called in separate thread.
337                 if (!Window.IsInstalled())
338                 {
339                     using var process = global::System.Diagnostics.Process.GetCurrentProcess();
340                     var processId = process.Id;
341                     var thread = global::System.Threading.Thread.CurrentThread.ManagedThreadId;
342                     var me = this.GetType().FullName;
343
344                     DebugFileLogging.Instance.WriteLog("[NUI][BaseHandle] This API called from separate thread. This API must be called from MainThread. \n" +
345                         $" process:{processId} thread:{thread}, disposing:{disposing}, isDisposed:{this.disposed}, isDisposeQueued:{this.isDisposeQueued}, me:{me}\n");
346
347                     Tizen.Log.Fatal("NUI", $"[NUI][BaseHandle] This API called from separate thread. This API must be called from MainThread. \n" +
348                         $" process:{processId} thread:{thread}, disposing:{disposing}, isDisposed:{this.disposed}, isDisposeQueued:{this.isDisposeQueued}, me:{me}\n");
349
350                     //to fix ArtApp black screen issue. this will be enabled after talking with ArtApp team and fixing it.
351                     // throw new global::System.InvalidOperationException("[NUI][BaseHandle] This API called from separate thread. This API must be called from MainThread. \n" +
352                     //     $" process:{process} thread:{thread}, disposing:{disposing}, isDisposed:{this.disposed}, isDisposeQueued:{this.isDisposeQueued}, me:{me}\n");
353                 }
354
355                 if (isDisposeQueued)
356                 {
357                     DebugFileLogging.Instance.WriteLog($"should not be here! (dead code) this will be removed!");
358
359                     Tizen.Log.Fatal("NUI", $"[NUI] should not be here! (dead code) this will be removed!");
360
361                     //to fix ArtApp black screen issue. this will be enabled after talking with ArtApp team and fixing it.
362                     // throw new global::System.Exception($"[NUI] should not be here! (dead code) this will be removed!");
363                     Dispose(DisposeTypes.Implicit);
364                 }
365                 else
366                 {
367                     Dispose(DisposeTypes.Explicit);
368                 }
369             }
370             else
371             {
372                 // Implicit call. user doesn't call Dispose(), so this object is added into DisposeQueue to be disposed automatically.
373                 if (!isDisposeQueued)
374                 {
375                     isDisposeQueued = true;
376                     DisposeQueue.Instance.Add(this);
377                 }
378             }
379
380             // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
381             // TODO: set large fields to null.
382         }
383
384
385         /// <summary>
386         /// Performs an action on this object with the given action name and attributes.
387         /// </summary>
388         /// <param name="actionName">The command for the action.</param>
389         /// <param name="attributes">The list of attributes for the action.</param>
390         /// <returns>The action is performed by the object or not.</returns>
391         /// <since_tizen> 3 </since_tizen>
392         public bool DoAction(string actionName, PropertyMap attributes)
393         {
394             bool ret = Interop.BaseHandle.DoAction(swigCPtr, actionName, PropertyMap.getCPtr(attributes));
395             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
396             return ret;
397         }
398
399         /// <summary>
400         /// Returns the type name for the Handle.<br />
401         /// Will return an empty string if the typename does not exist. This will happen for types that
402         /// have not registered with type-registry.
403         /// </summary>
404         /// <returns>The type name. Empty string if the typename does not exist.</returns>
405         /// <since_tizen> 3 </since_tizen>
406         public string GetTypeName()
407         {
408             string ret = Interop.BaseHandle.GetTypeName(swigCPtr);
409             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
410             return ret;
411         }
412
413         /// <summary>
414         /// Returns the type info for the Handle.<br />
415         /// </summary>
416         /// <param name="info">The type information.</param>
417         /// <returns>True If get the type info.</returns>
418         /// <since_tizen> 3 </since_tizen>
419         public bool GetTypeInfo(Tizen.NUI.TypeInfo info)
420         {
421             bool ret = Interop.BaseHandle.GetTypeInfo(swigCPtr, Tizen.NUI.TypeInfo.getCPtr(info));
422             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
423             return ret;
424         }
425
426         /// <summary>
427         /// Resets the handle.
428         /// </summary>
429         /// <since_tizen> 3 </since_tizen>
430         /// <remark>
431         /// This will be deprecated, please use Dispose() instead.
432         /// </remark>
433         public void Reset()
434         {
435             this.Dispose();
436             NUILog.Error("[ERROR] This(BaseHandle.Reset) will be deprecated, please use Dispose() instead!");
437         }
438
439         /// <summary>
440         /// To check the BaseHandle instance is equal or not.
441         /// </summary>
442         /// <param name="rhs">The baseHandle instance.</param>
443         /// <returns>True If equal.</returns>
444         /// <since_tizen> 3 </since_tizen>
445         public bool EqualTo(BaseHandle rhs)
446         {
447             bool ret = Interop.BaseHandle.EqualTo(swigCPtr, BaseHandle.getCPtr(rhs));
448             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
449             return ret;
450         }
451
452         /// <summary>
453         /// To check the BaseHandle instance is equal or not.
454         /// </summary>
455         /// <param name="rhs">The baseHandle instance.</param>
456         /// <returns>True If not equal.</returns>
457         /// <since_tizen> 3 </since_tizen>
458         public bool NotEqualTo(BaseHandle rhs)
459         {
460             bool ret = Interop.BaseHandle.NotEqualTo(swigCPtr, BaseHandle.getCPtr(rhs));
461             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
462             return ret;
463         }
464
465         /// <summary>
466         /// To check the BaseHandle instance has body or not.
467         /// </summary>
468         /// <returns>True If the baseHandle instance has body.</returns>
469         /// <since_tizen> 3 </since_tizen>
470         public bool HasBody()
471         {
472             if (swigCPtr.Handle == IntPtr.Zero)
473             {
474                 return false;
475             }
476
477             if (disposed == true)
478             {
479                 return false;
480             }
481             bool ret = Interop.BaseHandle.HasBody(swigCPtr);
482             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
483             return ret;
484         }
485
486         /// <summary>
487         /// To check the BaseHandle instance is equal or not.
488         /// </summary>
489         /// <param name="rhs">The baseHandle instance.</param>
490         /// <returns>True If equal.</returns>
491         /// <since_tizen> 3 </since_tizen>
492         public bool IsEqual(BaseHandle rhs)
493         {
494             if (disposed == true || rhs == null || !rhs.HasBody())
495             {
496                 return false;
497             }
498
499             bool ret = Interop.BaseHandle.IsEqual(swigCPtr, BaseHandle.getCPtr(rhs));
500             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
501             return ret;
502         }
503
504         internal static global::System.Runtime.InteropServices.HandleRef getCPtr(BaseHandle obj)
505         {
506             return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
507         }
508
509         internal void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
510         {
511             PropertySet?.Invoke(this, new PropertyChangedEventArgs(propertyName));
512         }
513
514         /// <summary>
515         /// Dispose.
516         /// </summary>
517         /// <since_tizen> 3 </since_tizen>
518         protected virtual void Dispose(DisposeTypes type)
519         {
520             if (disposed)
521             {
522                 return;
523             }
524
525             DebugFileLogging.Instance.WriteLog($"BaseHandle.Dispose({type}) START");
526
527             if (type == DisposeTypes.Explicit)
528             {
529                 //Called by User
530                 //Release your own managed resources here.
531                 //You should release all of your own disposable objects here.
532
533             }
534
535             //Release your own unmanaged resources here.
536             //You should not access any managed member here except static instance.
537             //because the execution order of Finalizes is non-deterministic.
538
539             //Unreference this instance from Registry.
540             if (registerMe)
541             {
542                 Registry.Unregister(this);
543             }
544
545             disposeDebuggingDispose(type);
546
547             if (SwigCPtr.Handle != IntPtr.Zero)
548             {
549                 var nativeSwigCPtr = swigCPtr.Handle;
550                 swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
551                 if (swigCMemOwn)
552                 {
553                     swigCMemOwn = false;
554                     ReleaseSwigCPtr(new global::System.Runtime.InteropServices.HandleRef(this, nativeSwigCPtr));
555                 }
556             }
557             else
558             {
559                 var me = this.GetType().FullName;
560                 DebugFileLogging.Instance.WriteLog($"[ERR] SwigCPtr is NULL, need to check! me:{me}");
561                 Log.Error("NUI", $"[ERR] SwigCPtr is NULL, need to check! me:{me}");
562             }
563
564             disposed = true;
565             DebugFileLogging.Instance.WriteLog($"BaseHandle.Dispose({type}) END");
566             DebugFileLogging.Instance.WriteLog($"=============================");
567             NUILog.Debug($"BaseHandle.Dispose({type}) END");
568             NUILog.Debug($"=============================");
569         }
570
571         /// <summary>
572         /// Release swigCPtr.
573         /// </summary>
574         /// <since_tizen> 6 </since_tizen>
575         /// This will not be public opened.
576         [EditorBrowsable(EditorBrowsableState.Never)]
577         protected virtual void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
578         {
579             Interop.BaseHandle.DeleteBaseHandle(swigCPtr.Handle);
580         }
581
582         /// <summary>
583         /// Contains event arguments for the FocusChangeRequested event.
584         /// </summary>
585         [Obsolete("Deprecated in API9; Will be removed in API11.")]
586         public class FocusRequestArgs : EventArgs
587         {
588
589             /// <summary>
590             /// Gets or sets a value that indicates the starting focus state of the element for which a focus change is requested.
591             /// </summary>
592             public bool Focus { get; set; }
593
594             /// <summary>
595             /// Gets or sets a value that indicates the ending focus state of the element for which a focus change is requested.
596             /// </summary>
597             public bool Result { get; set; }
598         }
599
600         internal global::System.Runtime.InteropServices.HandleRef SwigCPtr
601         {
602             get
603             {
604                 if (swigCPtr.Handle == IntPtr.Zero)
605                 {
606                     using var process = global::System.Diagnostics.Process.GetCurrentProcess();
607                     var processId = process.Id;
608                     var thread = global::System.Threading.Thread.CurrentThread.ManagedThreadId;
609                     var me = this.GetType().FullName;
610
611                     Tizen.Log.Fatal("NUI", $"SwigCPtr Error! NUI's native dali object is already disposed. " +
612                         $"OR the native dali object handle of NUI becomes null! \n" +
613                         $" process:{processId} thread:{thread}, isDisposed:{this.disposed}, isDisposeQueued:{this.isDisposeQueued}, me:{me}\n");
614
615                     Tizen.Log.Fatal("NUI", $"[ERROR] back trace!");
616                     global::System.Diagnostics.StackTrace st = new global::System.Diagnostics.StackTrace(true);
617                     for (int i = 0; i < st.FrameCount; i++)
618                     {
619                         global::System.Diagnostics.StackFrame sf = st.GetFrame(i);
620                         Tizen.Log.Fatal("NUI", " Method " + sf.GetMethod() + ":" + sf.GetFileName() + ":" + sf.GetFileLineNumber());
621                     }
622                     Tizen.Log.Fatal("NUI", "Error! just return here with null swigCPtr! this can cause unknown error or crash in next step");
623
624                     //to fix ArtApp black screen issue. this will be enabled after talking with ArtApp team and fixing it.
625                     // throw new ObjectDisposedException(nameof(SwigCPtr), $"Error! NUI's native dali object is already disposed. " +
626                     //     $"OR the native dali object handle of NUI becomes null! \n" +
627                     //     $" process:{process} thread:{thread}, isDisposed:{this.disposed}, isDisposeQueued:{this.isDisposeQueued}, me:{me}\n");
628                 }
629                 return swigCPtr;
630             }
631         }
632
633         internal bool IsNativeHandleInvalid()
634         {
635             return swigCPtr.Handle == IntPtr.Zero;
636         }
637
638         /// <summary>
639         /// swigCMemOwn
640         /// </summary>
641         [EditorBrowsable(EditorBrowsableState.Never)]
642         protected internal bool SwigCMemOwn => swigCMemOwn;
643
644         /// <summary>
645         /// The flag to check if it is already disposed of.
646         /// </summary>
647         [EditorBrowsable(EditorBrowsableState.Never)]
648         protected internal bool Disposed => disposed;
649
650         /// <summary>
651         /// The flag to check if it is disposed by DisposeQueue.
652         /// </summary>
653         [EditorBrowsable(EditorBrowsableState.Never)]
654         protected internal bool IsDisposeQueued => isDisposeQueued;
655
656         [Conditional("NUI_DISPOSE_DEBUG_ON")]
657         private void disposeDebuggingCtor()
658         {
659             DebugFileLogging.Instance.WriteLog($"type:{GetType()} copyNativeHandle:{swigCPtr.Handle.ToString("X8")}");
660             if (this is BaseComponents.View view)
661             {
662                 DebugFileLogging.Instance.WriteLog($"ID:{view.ID} Name:{view.Name}");
663                 //back trace
664                 global::System.Diagnostics.StackTrace st = new global::System.Diagnostics.StackTrace(true);
665                 for (int i = 0; i < st.FrameCount; i++)
666                 {
667                     global::System.Diagnostics.StackFrame sf = st.GetFrame(i);
668                     DebugFileLogging.Instance.WriteLog($"[{i}] {sf.GetMethod()}:{sf.GetFileName()}:{sf.GetFileLineNumber()}");
669                 }
670             }
671         }
672
673         [Conditional("NUI_DISPOSE_DEBUG_ON")]
674         private void disposeDebuggingDispose(DisposeTypes type)
675         {
676             DebugFileLogging.Instance.WriteLog($"swigCMemOwn:{swigCMemOwn} type:{GetType()} copyNativeHandle:{swigCPtr.Handle.ToString("X8")} HasBody:{HasBody()}");
677
678             if (HasBody())
679             {
680                 using var currentProcess = global::System.Diagnostics.Process.GetCurrentProcess();
681                 var process = currentProcess.Id;
682                 var thread = global::System.Threading.Thread.CurrentThread.ManagedThreadId;
683                 var me = this.GetType().FullName;
684                 var daliId = "unknown";
685                 var hash = this.GetType().GetHashCode();
686                 var name = "unknown";
687
688                 if (this is BaseComponents.View)
689                 {
690                     daliId = Interop.Actor.GetId(swigCPtr).ToString();
691                     name = Interop.Actor.GetName(swigCPtr);
692                     BaseObject tmp = new BaseObject(Interop.BaseHandle.GetBaseObject(swigCPtr), false);
693                     var refCnt = tmp.ReferenceCount();
694                     tmp.Dispose();
695                     if (refCnt > 2)
696                     {
697                         DebugFileLogging.Instance.WriteLog($"[ERR] reference count is over than 2. Could be a memory leak. Need to check! \n" +
698                             $" process:{process} thread:{thread}, isDisposed:{this.disposed}, isDisposeQueued:{this.isDisposeQueued}, me:{me} \n" +
699                             $" disposeType:{type}, name:{name}, daliID:{daliId}, hash:{hash}, refCnt:{refCnt}");
700
701                         Log.Error("NUI", $"[ERR] reference count is over than 2. Could be a memory leak. Need to check! \n" +
702                             $" process:{process} thread:{thread}, isDisposed:{this.disposed}, isDisposeQueued:{this.isDisposeQueued}, me:{me} \n" +
703                             $" disposeType:{type}, name:{name}, daliID:{daliId}, hash:{hash}, refCnt:{refCnt}");
704                     }
705                 }
706             }
707         }
708
709     }
710 }