Merge remote-tracking branch 'origin/master' into tizen
[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 (Thread.CurrentThread.ManagedThreadId != 1)
53             {
54                 Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
55
56                 StackTrace st = new StackTrace(true);
57                 for (int i = 0; i < st.FrameCount; i++)
58                 {
59                     StackFrame sf = st.GetFrame(i);
60                     Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
61                 }
62             }
63
64             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
65
66             NUILog.Debug($"(0x{swigCPtr.Handle:X})  Timer({milliSec}) Constructor!");
67         }
68         internal Timer(Timer timer) : this(Interop.Timer.new_Timer__SWIG_1(Timer.getCPtr(timer)), true)
69         {
70             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
71         }
72
73         internal Timer(global::System.IntPtr cPtr, bool cMemoryOwn) : base(Interop.Timer.Timer_SWIGUpcast(cPtr), cMemoryOwn)
74         {
75
76             _timerTickCallbackDelegate = OnTick;
77             _timerTickCallbackOfNative = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(_timerTickCallbackDelegate);
78
79             NUILog.Debug($"(0x{swigCPtr.Handle:X})Timer() contructor!");
80         }
81
82         /// <summary>
83         /// Destructor.
84         /// </summary>
85         ~Timer()
86         {
87             NUILog.Debug($"(0x{swigCPtr.Handle:X})Timer() distructor!, disposed={disposed}");
88         }
89
90         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
91         private delegate bool TickCallbackDelegate();
92
93         /// <summary>
94         /// @brief Event for the ticked signal, which can be used to subscribe or unsubscribe the event handler
95         /// provided by the user. The ticked signal is emitted after specified time interval.<br />
96         /// </summary>
97         /// <since_tizen> 3 </since_tizen>
98         public event EventHandlerWithReturnType<object, TickEventArgs, bool> Tick
99         {
100             add
101             {
102                 if (Thread.CurrentThread.ManagedThreadId != 1)
103                 {
104                     Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
105
106                     StackTrace st = new StackTrace(true);
107                     for (int i = 0; i < st.FrameCount; i++)
108                     {
109                         StackFrame sf = st.GetFrame(i);
110                         Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
111                     }
112                 }
113
114
115                 if (_timerTickEventHandler == null && disposed == false)
116                 {
117                     TickSignal().Connect(_timerTickCallbackOfNative);
118                 }
119                 _timerTickEventHandler += value;
120             }
121             remove
122             {
123                 if (Thread.CurrentThread.ManagedThreadId != 1)
124                 {
125                     Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
126
127                     StackTrace st = new StackTrace(true);
128                     for (int i = 0; i < st.FrameCount; i++)
129                     {
130                         StackFrame sf = st.GetFrame(i);
131                         Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
132                     }
133                 }
134
135                 _timerTickEventHandler -= value;
136                 if (_timerTickEventHandler == null && TickSignal().Empty() == false)
137                 {
138                     TickSignal().Disconnect(_timerTickCallbackOfNative);
139                 }
140             }
141         }
142
143         /// <summary>
144         /// Gets/Sets the interval of the timer.
145         /// </summary>
146         /// <remarks>For setter, this sets a new interval on the timer and starts the timer. <br />
147         /// Cancels the previous timer.
148         /// </remarks>
149         /// <since_tizen> 4 </since_tizen>
150         public uint Interval
151         {
152             get
153             {
154                 if (Thread.CurrentThread.ManagedThreadId != 1)
155                 {
156                     Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
157
158                     StackTrace st = new StackTrace(true);
159                     for (int i = 0; i < st.FrameCount; i++)
160                     {
161                         StackFrame sf = st.GetFrame(i);
162                         Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
163                     }
164                 }
165
166                 return GetInterval();
167             }
168             set
169             {
170                 if (Thread.CurrentThread.ManagedThreadId != 1)
171                 {
172                     Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
173
174                     StackTrace st = new StackTrace(true);
175                     for (int i = 0; i < st.FrameCount; i++)
176                     {
177                         StackFrame sf = st.GetFrame(i);
178                         Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
179                     }
180                 }
181
182                 SetInterval(value);
183             }
184         }
185
186         /// <summary>
187         /// Starts the timer.<br />
188         /// In case a timer is already running, its time is reset and the timer is restarted.<br />
189         /// </summary>
190         /// <since_tizen> 3 </since_tizen>
191         public void Start()
192         {
193             if (Thread.CurrentThread.ManagedThreadId != 1)
194             {
195                 Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
196
197                 StackTrace st = new StackTrace(true);
198                 for (int i = 0; i < st.FrameCount; i++)
199                 {
200                     StackFrame sf = st.GetFrame(i);
201                     Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
202                 }
203             }
204
205             if (swigCPtr.Handle == global::System.IntPtr.Zero || disposed)
206             {
207                 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!");
208                 return;
209             }
210
211             played = true;
212             Interop.Timer.Timer_Start(swigCPtr);
213
214             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
215         }
216
217         /// <summary>
218         /// Stops the timer.
219         /// </summary>
220         /// <since_tizen> 3 </since_tizen>
221         public void Stop()
222         {
223             if (Thread.CurrentThread.ManagedThreadId != 1)
224             {
225                 Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
226
227
228                 StackTrace st = new StackTrace(true);
229                 for (int i = 0; i < st.FrameCount; i++)
230                 {
231                     StackFrame sf = st.GetFrame(i);
232                     Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
233                 }
234             }
235
236             if (swigCPtr.Handle == global::System.IntPtr.Zero || disposed)
237             {
238                 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!");
239                 return;
240             }
241
242             played = false;
243             Interop.Timer.Timer_Stop(swigCPtr);
244
245             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
246         }
247
248         /// <summary>
249         /// Tells whether the timer is running.
250         /// </summary>
251         /// <returns>Whether the timer is started or not.</returns>
252         /// <since_tizen> 3 </since_tizen>
253         public bool IsRunning()
254         {
255             if (Thread.CurrentThread.ManagedThreadId != 1)
256             {
257                 Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
258
259                 StackTrace st = new StackTrace(true);
260                 for (int i = 0; i < st.FrameCount; i++)
261                 {
262                     StackFrame sf = st.GetFrame(i);
263                     Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
264                 }
265             }
266
267             if (swigCPtr.Handle == global::System.IntPtr.Zero || disposed)
268             {
269                 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!");
270                 return false;
271             }
272
273             bool ret = Interop.Timer.Timer_IsRunning(swigCPtr);
274             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
275             return ret;
276         }
277
278         internal static global::System.Runtime.InteropServices.HandleRef getCPtr(Timer obj)
279         {
280             return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr;
281         }
282
283         /// <summary>
284         /// Sets a new interval on the timer and starts the timer.<br />
285         /// Cancels the previous timer.<br />
286         /// </summary>
287         /// <param name="milliSec">MilliSec interval in milliseconds.</param>
288         internal void SetInterval(uint milliSec)
289         {
290             NUILog.Debug($"(0x{swigCPtr.Handle:X})SetInterval({milliSec})");
291
292             if (swigCPtr.Handle == global::System.IntPtr.Zero || disposed)
293             {
294                 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!");
295                 return;
296             }
297
298             played = true;
299
300             Interop.Timer.Timer_SetInterval(swigCPtr, milliSec);
301             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
302         }
303
304         internal uint GetInterval()
305         {
306             if(swigCPtr.Handle == global::System.IntPtr.Zero || disposed)
307             {
308                 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!");
309                 return 0;
310             }
311
312             uint ret = Interop.Timer.Timer_GetInterval(swigCPtr);
313             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
314             return ret;
315         }
316
317         internal TimerSignalType TickSignal()
318         {
319             TimerSignalType ret = new TimerSignalType(Interop.Timer.Timer_TickSignal(swigCPtr), false);
320             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
321             return ret;
322         }
323
324         /// <summary>
325         /// Dispose.
326         /// </summary>
327         /// <since_tizen> 3 </since_tizen>
328         protected override void Dispose(DisposeTypes type)
329         {
330             if (Thread.CurrentThread.ManagedThreadId != 1)
331             {
332                 Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
333
334                 StackTrace st = new StackTrace(true);
335                 for (int i = 0; i < st.FrameCount; i++)
336                 {
337                     StackFrame sf = st.GetFrame(i);
338                     Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
339                 }
340             }
341
342             NUILog.Debug($"(0x{swigCPtr.Handle:X}) Timer.Dispose(type={type}, disposed={disposed})");
343
344             if (this != null && _timerTickCallbackDelegate != null)
345             {
346                 TickSignal().Disconnect(_timerTickCallbackOfNative);
347             }
348
349             if (disposed)
350             {
351                 return;
352             }
353
354             played = false;
355             base.Dispose(type);
356         }
357
358         /// This will not be public opened.
359         [EditorBrowsable(EditorBrowsableState.Never)]
360         protected override void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
361         {
362             Interop.Timer.delete_Timer(swigCPtr);
363         }
364
365         private bool OnTick()
366         {
367             TickEventArgs e = new TickEventArgs();
368
369             if (played == false)
370             {
371                 Tizen.Log.Fatal("NUI", $"(0x{swigCPtr.Handle:X}) OnTick() is called even played is false!");
372                 //throw new System.InvalidOperationException($"OnTick() excpetion!");
373             }
374
375             if (_timerTickEventHandler != null && played == true)
376             {
377                 //here we send all data to user event handlers
378                 return _timerTickEventHandler(this, e);
379             }
380             return false;
381         }
382
383         /// <summary>
384         /// Event arguments that passed via the tick event.
385         /// </summary>
386         /// <since_tizen> 3 </since_tizen>
387         public class TickEventArgs : EventArgs
388         {
389         }
390     }
391
392 }
393