[NUI] Add dispose checking in just a few methods of Timer class (#1340)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Timer.cs
1 /*
2  * Copyright(c) 2017 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.Runtime.InteropServices;
19 using System.ComponentModel;
20 using System.Threading;
21 using System.Diagnostics;
22
23 namespace Tizen.NUI
24 {
25     /// <summary>
26     /// Mechanism to issue simple periodic or one-shot events.<br />
27     /// Timer is provided for application developers to be able to issue
28     /// simple periodic or one-shot events. Please note that the timer
29     /// callback functions should return as soon as possible because they
30     /// block the next SignalTick. Please note that timer signals are not
31     /// in sync with DALi's render timer.<br />
32     /// This class is a handle class so it can be stack allocated and used
33     /// as a member.<br />
34     /// </summary>
35     /// <since_tizen> 3 </since_tizen>
36     public class Timer : BaseHandle
37     {
38         private bool played = false;
39         private EventHandlerWithReturnType<object, TickEventArgs, bool> _timerTickEventHandler;
40         private TickCallbackDelegate _timerTickCallbackDelegate;
41
42         private System.IntPtr _timerTickCallbackOfNative;
43
44         /// <summary>
45         /// Creates a tick timer that emits periodic signal.
46         /// </summary>
47         /// <param name="milliSec">Interval in milliseconds.</param>
48         /// <returns>A new timer.</returns>
49         /// <since_tizen> 3 </since_tizen>
50         public Timer(uint milliSec) : this(Interop.Timer.Timer_New(milliSec), true)
51         {
52             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
53
54             NUILog.Debug($"(0x{swigCPtr.Handle:X})  Timer({milliSec}) Constructor!");
55         }
56         internal Timer(Timer timer) : this(Interop.Timer.new_Timer__SWIG_1(Timer.getCPtr(timer)), true)
57         {
58             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
59         }
60
61         internal Timer(global::System.IntPtr cPtr, bool cMemoryOwn) : base(Interop.Timer.Timer_SWIGUpcast(cPtr), cMemoryOwn)
62         {
63
64             _timerTickCallbackDelegate = OnTick;
65             _timerTickCallbackOfNative = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(_timerTickCallbackDelegate);
66
67             NUILog.Debug($"(0x{swigCPtr.Handle:X})Timer() contructor!");
68         }
69
70         /// <summary>
71         /// Destructor.
72         /// </summary>
73         ~Timer()
74         {
75             NUILog.Debug($"(0x{swigCPtr.Handle:X})Timer() distructor!, disposed={disposed}");
76         }
77
78         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
79         private delegate bool TickCallbackDelegate();
80
81         /// <summary>
82         /// @brief Event for the ticked signal, which can be used to subscribe or unsubscribe the event handler
83         /// provided by the user. The ticked signal is emitted after specified time interval.<br />
84         /// </summary>
85         /// <since_tizen> 3 </since_tizen>
86         public event EventHandlerWithReturnType<object, TickEventArgs, bool> Tick
87         {
88             add
89             {
90                 if (_timerTickEventHandler == null && disposed == false)
91                 {
92                     TickSignal().Connect(_timerTickCallbackOfNative);
93                 }
94                 _timerTickEventHandler += value;
95             }
96             remove
97             {
98                 _timerTickEventHandler -= value;
99                 if (_timerTickEventHandler == null && TickSignal().Empty() == false)
100                 {
101                     TickSignal().Disconnect(_timerTickCallbackOfNative);
102                 }
103             }
104         }
105
106         /// <summary>
107         /// Gets/Sets the interval of the timer.
108         /// </summary>
109         /// <remarks>For setter, this sets a new interval on the timer and starts the timer. <br />
110         /// Cancels the previous timer.
111         /// </remarks>
112         /// <since_tizen> 4 </since_tizen>
113         public uint Interval
114         {
115             get
116             {
117                 return GetInterval();
118             }
119             set
120             {
121                 SetInterval(value);
122             }
123         }
124
125         /// <summary>
126         /// Starts the timer.<br />
127         /// In case a timer is already running, its time is reset and the timer is restarted.<br />
128         /// </summary>
129         /// <since_tizen> 3 </since_tizen>
130         public void Start()
131         {
132             if (Thread.CurrentThread.ManagedThreadId != 1)
133             {
134                 Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
135
136                 StackTrace st = new StackTrace(true);
137                 for (int i = 0; i < st.FrameCount; i++)
138                 {
139                     StackFrame sf = st.GetFrame(i);
140                     Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
141                 }
142             }
143
144             if (swigCPtr.Handle == global::System.IntPtr.Zero || disposed)
145             {
146                 NUILog.Error("[ERR] already disposed! can not get this done! just return here! please make sure that the handle gets free when using explicit Dispose()! For example, timer.Dispose(); timer = null; this must be done!");
147                 return;
148             }
149
150             played = true;
151             Interop.Timer.Timer_Start(swigCPtr);
152
153             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
154         }
155
156         /// <summary>
157         /// Stops the timer.
158         /// </summary>
159         /// <since_tizen> 3 </since_tizen>
160         public void Stop()
161         {
162             if (Thread.CurrentThread.ManagedThreadId != 1)
163             {
164                 Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
165
166
167                 StackTrace st = new StackTrace(true);
168                 for (int i = 0; i < st.FrameCount; i++)
169                 {
170                     StackFrame sf = st.GetFrame(i);
171                     Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
172                 }
173             }
174
175             if (swigCPtr.Handle == global::System.IntPtr.Zero || disposed)
176             {
177                 NUILog.Error("[ERR] already disposed! can not get this done! just return here! please make sure that the handle gets free when using explicit Dispose()! For example, timer.Dispose(); timer = null; this must be done!");
178                 return;
179             }
180
181             played = false;
182             Interop.Timer.Timer_Stop(swigCPtr);
183
184             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
185         }
186
187         /// <summary>
188         /// Tells whether the timer is running.
189         /// </summary>
190         /// <returns>Whether the timer is started or not.</returns>
191         /// <since_tizen> 3 </since_tizen>
192         public bool IsRunning()
193         {
194             if (Thread.CurrentThread.ManagedThreadId != 1)
195             {
196                 Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
197
198                 StackTrace st = new StackTrace(true);
199                 for (int i = 0; i < st.FrameCount; i++)
200                 {
201                     StackFrame sf = st.GetFrame(i);
202                     Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
203                 }
204             }
205
206             if (swigCPtr.Handle == global::System.IntPtr.Zero || disposed)
207             {
208                 NUILog.Error("[ERR] already disposed! can not get this done! just return here! please make sure that the handle gets free when using explicit Dispose()! For example, timer.Dispose(); timer = null; this must be done!");
209                 return false;
210             }
211
212             bool ret = Interop.Timer.Timer_IsRunning(swigCPtr);
213             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
214             return ret;
215         }
216
217         internal static global::System.Runtime.InteropServices.HandleRef getCPtr(Timer obj)
218         {
219             return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
220         }
221
222         /// <summary>
223         /// Sets a new interval on the timer and starts the timer.<br />
224         /// Cancels the previous timer.<br />
225         /// </summary>
226         /// <param name="milliSec">MilliSec interval in milliseconds.</param>
227         internal void SetInterval(uint milliSec)
228         {
229             NUILog.Debug($"(0x{swigCPtr.Handle:X})SetInterval({milliSec})");
230
231             if (swigCPtr.Handle == global::System.IntPtr.Zero || disposed)
232             {
233                 NUILog.Error("[ERR] already disposed! can not get this done! just return here! please make sure that the handle gets free when using explicit Dispose()! For example, timer.Dispose(); timer = null; this must be done!");
234                 return;
235             }
236
237             played = true;
238
239             Interop.Timer.Timer_SetInterval(swigCPtr, milliSec);
240             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
241         }
242
243         internal uint GetInterval()
244         {
245             if(swigCPtr.Handle == global::System.IntPtr.Zero || disposed)
246             {
247                 NUILog.Error("[ERR] already disposed! can not get this done! just return here! please make sure that the handle gets free when using explicit Dispose()! For example, timer.Dispose(); timer = null; this must be done!");
248                 return 0;
249             }
250
251             uint ret = Interop.Timer.Timer_GetInterval(swigCPtr);
252             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
253             return ret;
254         }
255
256         internal TimerSignalType TickSignal()
257         {
258             TimerSignalType ret = new TimerSignalType(Interop.Timer.Timer_TickSignal(swigCPtr), false);
259             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
260             return ret;
261         }
262
263         /// <summary>
264         /// Dispose.
265         /// </summary>
266         /// <since_tizen> 3 </since_tizen>
267         protected override void Dispose(DisposeTypes type)
268         {
269             NUILog.Debug($"(0x{swigCPtr.Handle:X}) Timer.Dispose(type={type}, disposed={disposed})");
270
271             if (this != null && _timerTickCallbackDelegate != null)
272             {
273                 TickSignal().Disconnect(_timerTickCallbackOfNative);
274             }
275
276             if (disposed)
277             {
278                 return;
279             }
280
281             played = false;
282             base.Dispose(type);
283         }
284
285         /// This will not be public opened.
286         [EditorBrowsable(EditorBrowsableState.Never)]
287         protected override void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
288         {
289             Interop.Timer.delete_Timer(swigCPtr);
290         }
291
292         private bool OnTick()
293         {
294             TickEventArgs e = new TickEventArgs();
295
296             if (played == false)
297             {
298                 Tizen.Log.Fatal("NUI", $"(0x{swigCPtr.Handle:X}) OnTick() is called even played is false!");
299                 //throw new System.InvalidOperationException($"OnTick() excpetion!");
300             }
301
302             if (_timerTickEventHandler != null && played == true)
303             {
304                 //here we send all data to user event handlers
305                 return _timerTickEventHandler(this, e);
306             }
307             return false;
308         }
309
310         /// <summary>
311         /// Event arguments that passed via the tick event.
312         /// </summary>
313         /// <since_tizen> 3 </since_tizen>
314         public class TickEventArgs : EventArgs
315         {
316         }
317     }
318
319 }
320