Updated all code to new format
[platform/core/uifw/dali-adaptor.git] / dali / internal / system / macos / timer-impl-mac.cpp
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
18 // CLASS HEADER
19 #include <dali/internal/system/common/timer-impl.h>
20 #include "extern-definitions.h"
21
22 namespace Dali::Internal::Adaptor
23 {
24 /**
25  * Struct to hide away macOS implementation details
26  */
27 struct Timer::Impl
28 {
29   Impl(Timer* parent, unsigned int milliSec)
30   : mTimer(CreateTimer(parent, milliSec))
31   {
32   }
33
34   ~Impl()
35   {
36     Stop();
37   }
38
39   static void TimerProc(CFRunLoopTimerRef timer, void* info);
40
41   void Start();
42   void Stop();
43   void Reset(Timer* parent, unsigned int milliSec);
44
45   unsigned int GetInterval() const noexcept
46   {
47     return CFRunLoopTimerGetInterval(mTimer.get()) * 1000.0;
48   }
49
50   bool IsRunning() const noexcept
51   {
52     return CFRunLoopTimerIsValid(mTimer.get());
53   }
54
55 private:
56   CFRef<CFRunLoopTimerRef> CreateTimer(Timer* parent, unsigned int milliSec);
57
58   CFRef<CFRunLoopTimerRef> mTimer;
59 };
60
61 void Timer::Impl::TimerProc(CFRunLoopTimerRef timer, void* info)
62 {
63   auto* pTimer = static_cast<Timer*>(info);
64   pTimer->Tick();
65 }
66
67 void Timer::Impl::Start()
68 {
69   if(!IsRunning())
70   {
71     auto runLoop = CFRunLoopGetMain();
72     CFRunLoopAddTimer(runLoop, mTimer.get(), kCFRunLoopDefaultMode);
73   }
74 }
75
76 void Timer::Impl::Stop()
77 {
78   if(IsRunning())
79   {
80     CFRunLoopTimerContext context;
81     CFRunLoopTimerGetContext(mTimer.get(), &context);
82     const auto interval = CFRunLoopTimerGetInterval(mTimer.get());
83     CFRunLoopTimerInvalidate(mTimer.get());
84
85     // After we invalidate the timer, we can't reuse it, so we create
86     // a new timer for case the user calls Start again
87     const auto fireDate = CFAbsoluteTimeGetCurrent() + interval;
88     mTimer.reset(CFRunLoopTimerCreate(
89       kCFAllocatorDefault,
90       fireDate,
91       interval,
92       0,
93       0,
94       TimerProc,
95       &context));
96   }
97 }
98
99 void Timer::Impl::Reset(Timer* parent, unsigned int milliSec)
100 {
101   Stop();
102   mTimer = CreateTimer(parent, milliSec);
103   Start();
104 }
105
106 CFRef<CFRunLoopTimerRef>
107 Timer::Impl::CreateTimer(Timer* parent, unsigned int milliSec)
108 {
109   const auto            interval = static_cast<CFAbsoluteTime>(milliSec) / 1000;
110   const auto            fireDate = CFAbsoluteTimeGetCurrent() + interval;
111   CFRunLoopTimerContext context =
112     {
113       .version = 0,
114       .info    = parent,
115       .retain  = nullptr,
116       .release = nullptr,
117     };
118
119   return MakeRef(CFRunLoopTimerCreate(
120     kCFAllocatorDefault,
121     fireDate,
122     interval,
123     0,
124     0,
125     TimerProc,
126     &context));
127 }
128
129 TimerPtr Timer::New(unsigned int milliSec)
130 {
131   return new Timer(milliSec);
132 }
133
134 Timer::Timer(unsigned int milliSec)
135 : mImpl(new Impl(this, milliSec))
136 {
137 }
138
139 Timer::~Timer()
140 {
141   // stop timers
142   Stop();
143
144   delete mImpl;
145   mImpl = NULL;
146 }
147
148 void Timer::Start()
149 {
150   mImpl->Start();
151 }
152
153 void Timer::Stop()
154 {
155   mImpl->Stop();
156 }
157
158 void Timer::Pause()
159 {
160 }
161
162 void Timer::Resume()
163 {
164 }
165
166 void Timer::SetInterval(unsigned int interval, bool restart)
167 {
168   mImpl->Reset(this, interval);
169 }
170
171 unsigned int Timer::GetInterval() const
172 {
173   return mImpl->GetInterval();
174 }
175
176 bool Timer::Tick()
177 {
178   // Guard against destruction during signal emission
179   Dali::Timer handle(this);
180
181   bool retVal(false);
182
183   // Override with new signal if used
184   if(!mTickSignal.Empty())
185   {
186     retVal = mTickSignal.Emit();
187
188     // Timer stops if return value is false
189     if(retVal == false)
190     {
191       Stop();
192     }
193     else
194     {
195       retVal = true; // continue emission
196     }
197   }
198   else // no callbacks registered
199   {
200     // periodic timer is started but nobody listens, continue
201     retVal = true;
202   }
203
204   return retVal;
205 }
206
207 Dali::Timer::TimerSignalType& Timer::TickSignal()
208 {
209   return mTickSignal;
210 }
211
212 bool Timer::IsRunning() const
213 {
214   return mImpl->IsRunning();
215 }
216
217 } // namespace Dali::Internal::Adaptor