[NUI] Format all files
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Utility / Timer.cs
1 /*
2  * Copyright(c) 2021 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.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.NewTimer(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(cPtr, cMemoryOwn)
62         {
63             timerTickCallbackDelegate = OnTick;
64             timerTickCallbackOfNative = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate<System.Delegate>(timerTickCallbackDelegate);
65
66             NUILog.Debug($"(0x{SwigCPtr.Handle:X})Timer() contructor!");
67         }
68
69         /// <summary>
70         /// Destructor.
71         /// </summary>
72         ~Timer()
73         {
74             Tizen.Log.Debug("NUI", $"(0x{SwigCPtr.Handle:X})Timer() distructor!, disposed={disposed}");
75         }
76
77         [UnmanagedFunctionPointer(CallingConvention.StdCall)]
78         private delegate bool TickCallbackDelegate();
79
80         /// <summary>
81         /// @brief Event for the ticked signal, which can be used to subscribe or unsubscribe the event handler
82         /// provided by the user. The ticked signal is emitted after specified time interval.<br />
83         /// </summary>
84         /// <since_tizen> 3 </since_tizen>
85         public event EventHandlerWithReturnType<object, TickEventArgs, bool> Tick
86         {
87             add
88             {
89                 if (timerTickEventHandler == null && disposed == false)
90                 {
91                     TickSignal().Connect(timerTickCallbackOfNative);
92                 }
93                 timerTickEventHandler += value;
94             }
95             remove
96             {
97                 timerTickEventHandler -= value;
98                 if (timerTickEventHandler == null && TickSignal().Empty() == false)
99                 {
100                     TickSignal().Disconnect(timerTickCallbackOfNative);
101                 }
102             }
103         }
104
105         /// <summary>
106         /// Gets/Sets the interval of the timer.
107         /// </summary>
108         /// <remarks>For setter, this sets a new interval on the timer and starts the timer. <br />
109         /// Cancels the previous timer.
110         /// </remarks>
111         /// <since_tizen> 4 </since_tizen>
112         public uint Interval
113         {
114             get
115             {
116                 return GetInterval();
117             }
118             set
119             {
120                 SetInterval(value);
121             }
122         }
123
124         /// <summary>
125         /// Starts the timer.<br />
126         /// In case a timer is already running, its time is reset and the timer is restarted.<br />
127         /// </summary>
128         /// <since_tizen> 3 </since_tizen>
129         public void Start()
130         {
131             if (Thread.CurrentThread.ManagedThreadId != 1)
132             {
133                 Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
134
135                 StackTrace st = new StackTrace(true);
136                 for (int i = 0; i < st.FrameCount; i++)
137                 {
138                     StackFrame sf = st.GetFrame(i);
139                     Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
140                 }
141             }
142
143             if (SwigCPtr.Handle == global::System.IntPtr.Zero || disposed)
144             {
145                 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!");
146                 return;
147             }
148
149             played = true;
150             Interop.Timer.Start(SwigCPtr);
151
152             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
153         }
154
155         /// <summary>
156         /// Stops the timer.
157         /// </summary>
158         /// <since_tizen> 3 </since_tizen>
159         public void Stop()
160         {
161             if (Thread.CurrentThread.ManagedThreadId != 1)
162             {
163                 Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
164
165                 StackTrace st = new StackTrace(true);
166                 for (int i = 0; i < st.FrameCount; i++)
167                 {
168                     StackFrame sf = st.GetFrame(i);
169                     Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
170                 }
171             }
172
173             if (SwigCPtr.Handle == global::System.IntPtr.Zero || disposed)
174             {
175                 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!");
176                 return;
177             }
178
179             played = false;
180             Interop.Timer.Stop(SwigCPtr);
181
182             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
183         }
184
185         /// <summary>
186         /// Tells whether the timer is running.
187         /// </summary>
188         /// <returns>Whether the timer is started or not.</returns>
189         /// <since_tizen> 3 </since_tizen>
190         public bool IsRunning()
191         {
192             if (Thread.CurrentThread.ManagedThreadId != 1)
193             {
194                 Tizen.Log.Error("NUI", "current threadID : " + Thread.CurrentThread.ManagedThreadId);
195
196                 StackTrace st = new StackTrace(true);
197                 for (int i = 0; i < st.FrameCount; i++)
198                 {
199                     StackFrame sf = st.GetFrame(i);
200                     Tizen.Log.Error("NUI", " Method " + sf.GetMethod());
201                 }
202             }
203
204             if (SwigCPtr.Handle == global::System.IntPtr.Zero || disposed)
205             {
206                 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!");
207                 return false;
208             }
209
210             bool ret = Interop.Timer.IsRunning(SwigCPtr);
211             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
212             return ret;
213         }
214
215         internal static global::System.Runtime.InteropServices.HandleRef getCPtr(Timer obj)
216         {
217             return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.SwigCPtr;
218         }
219
220         /// <summary>
221         /// Sets a new interval on the timer and starts the timer.<br />
222         /// Cancels the previous timer.<br />
223         /// </summary>
224         /// <param name="milliSec">MilliSec interval in milliseconds.</param>
225         internal void SetInterval(uint milliSec)
226         {
227             NUILog.Debug($"(0x{SwigCPtr.Handle:X})SetInterval({milliSec})");
228
229             if (SwigCPtr.Handle == global::System.IntPtr.Zero || disposed)
230             {
231                 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!");
232                 return;
233             }
234
235             played = true;
236
237             Interop.Timer.SetInterval(SwigCPtr, milliSec);
238             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
239         }
240
241         internal uint GetInterval()
242         {
243             if (SwigCPtr.Handle == global::System.IntPtr.Zero || disposed)
244             {
245                 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!");
246                 return 0;
247             }
248
249             uint ret = Interop.Timer.GetInterval(SwigCPtr);
250             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
251             return ret;
252         }
253
254         internal TimerSignalType TickSignal()
255         {
256             TimerSignalType ret = new TimerSignalType(Interop.Timer.TickSignal(SwigCPtr), false);
257             if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
258             return ret;
259         }
260
261         /// <summary>
262         /// Dispose.
263         /// </summary>
264         /// <since_tizen> 3 </since_tizen>
265         protected override void Dispose(DisposeTypes type)
266         {
267             NUILog.Debug($"(0x{SwigCPtr.Handle:X}) Timer.Dispose(type={type}, disposed={disposed})");
268
269             if (this != null && timerTickCallbackDelegate != null)
270             {
271                 TickSignal().Disconnect(timerTickCallbackOfNative);
272             }
273
274             if (disposed)
275             {
276                 return;
277             }
278
279             played = false;
280             base.Dispose(type);
281         }
282
283         /// This will not be public opened.
284         [EditorBrowsable(EditorBrowsableState.Never)]
285         protected override void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
286         {
287             Interop.Timer.DeleteTimer(swigCPtr);
288         }
289
290         private bool OnTick()
291         {
292             TickEventArgs e = new TickEventArgs();
293
294             if (played == false)
295             {
296                 Tizen.Log.Fatal("NUI", $"(0x{SwigCPtr.Handle:X}) OnTick() is called even played is false!");
297                 //throw new System.InvalidOperationException($"OnTick() excpetion!");
298             }
299
300             if (timerTickEventHandler != null && played == true)
301             {
302                 //here we send all data to user event handlers
303                 return timerTickEventHandler(this, e);
304             }
305             return false;
306         }
307
308         /// <summary>
309         /// Event arguments that passed via the tick event.
310         /// </summary>
311         /// <since_tizen> 3 </since_tizen>
312         public class TickEventArgs : EventArgs
313         {
314         }
315     }
316 }