26class Timer::TimerThread :
private Thread,
27 private DeletedAtShutdown,
31 using LockType = CriticalSection;
33 TimerThread() : Thread (
"JUCE Timer")
39 ~TimerThread()
override
42 callbackArrived.signal();
44 jassert (instance ==
this || instance ==
nullptr);
53 ReferenceCountedObjectPtr<CallTimersMessage> messageToSend (
new CallTimersMessage());
58 auto elapsed = (int) (now >= lastTime ? (now - lastTime)
59 : (std::numeric_limits<uint32>::max() - (lastTime - now)));
62 auto timeUntilFirstTimer = getTimeUntilFirstTimer (elapsed);
64 if (timeUntilFirstTimer <= 0)
66 if (callbackArrived.wait (0))
72 messageToSend->post();
74 if (! callbackArrived.wait (300))
79 messageToSend->post();
88 wait (jlimit (1, 100, timeUntilFirstTimer));
98 while (! timers.empty())
100 auto& first = timers.front();
102 if (first.countdownMs > 0)
105 auto* timer = first.timer;
106 first.countdownMs = timer->timerPeriodMs;
107 shuffleTimerBackInQueue (0);
114 timer->timerCallback();
123 callbackArrived.signal();
126 void callTimersSynchronously()
139 static inline void add (
Timer* tim)
noexcept
141 if (instance ==
nullptr)
142 instance =
new TimerThread();
144 instance->addTimer (tim);
147 static inline void remove (
Timer* tim)
noexcept
149 if (instance !=
nullptr)
150 instance->removeTimer (tim);
153 static inline void resetCounter (
Timer* tim)
noexcept
155 if (instance !=
nullptr)
156 instance->resetTimerCounter (tim);
159 static TimerThread* instance;
160 static LockType lock;
163 struct TimerCountdown
169 std::vector<TimerCountdown> timers;
171 WaitableEvent callbackArrived;
173 struct CallTimersMessage :
public MessageManager::MessageBase
175 CallTimersMessage() {}
177 void messageCallback()
override
179 if (instance !=
nullptr)
180 instance->callTimers();
185 void addTimer (
Timer* t)
189 jassert (std::find_if (timers.begin(), timers.end(),
190 [t](TimerCountdown i) { return i.timer == t; }) == timers.end());
192 auto pos = timers.size();
194 timers.push_back ({ t, t->timerPeriodMs });
195 t->positionInQueue = pos;
196 shuffleTimerForwardInQueue (pos);
200 void removeTimer (
Timer* t)
202 auto pos = t->positionInQueue;
203 auto lastIndex = timers.size() - 1;
205 jassert (pos <= lastIndex);
206 jassert (timers[pos].timer == t);
208 for (
auto i = pos; i < lastIndex; ++i)
210 timers[i] = timers[i + 1];
211 timers[i].timer->positionInQueue = i;
217 void resetTimerCounter (
Timer* t)
noexcept
219 auto pos = t->positionInQueue;
221 jassert (pos < timers.size());
222 jassert (timers[pos].timer == t);
224 auto lastCountdown = timers[pos].countdownMs;
225 auto newCountdown = t->timerPeriodMs;
227 if (newCountdown != lastCountdown)
229 timers[pos].countdownMs = newCountdown;
231 if (newCountdown > lastCountdown)
232 shuffleTimerBackInQueue (pos);
234 shuffleTimerForwardInQueue (pos);
240 void shuffleTimerBackInQueue (
size_t pos)
242 auto numTimers = timers.size();
244 if (pos < numTimers - 1)
246 auto t = timers[pos];
252 if (next == numTimers || timers[next].countdownMs >= t.countdownMs)
255 timers[pos] = timers[next];
256 timers[pos].timer->positionInQueue = pos;
262 t.timer->positionInQueue = pos;
266 void shuffleTimerForwardInQueue (
size_t pos)
270 auto t = timers[pos];
274 auto& prev = timers[(size_t) pos - 1];
276 if (prev.countdownMs <= t.countdownMs)
280 timers[pos].timer->positionInQueue = pos;
286 t.timer->positionInQueue = pos;
290 int getTimeUntilFirstTimer (
int numMillisecsElapsed)
297 for (
auto& t : timers)
298 t.countdownMs -= numMillisecsElapsed;
300 return timers.front().countdownMs;
303 void handleAsyncUpdate()
override
308 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimerThread)
311Timer::TimerThread* Timer::TimerThread::instance =
nullptr;
312Timer::TimerThread::LockType Timer::TimerThread::lock;
327 JUCE_ASSERT_MESSAGE_MANAGER_EXISTS
332 timerPeriodMs = jmax (1, interval);
335 TimerThread::add (
this);
337 TimerThread::resetCounter (
this);
352 if (timerPeriodMs > 0)
354 TimerThread::remove (
this);
361 if (TimerThread::instance !=
nullptr)
362 TimerThread::instance->callTimersSynchronously();
365struct LambdaInvoker :
private Timer
367 LambdaInvoker (
int milliseconds, std::function<
void()> f) : function (f)
372 void timerCallback()
override
379 std::function<void()> function;
381 JUCE_DECLARE_NON_COPYABLE (LambdaInvoker)
386 new LambdaInvoker (milliseconds, f);
void triggerAsyncUpdate()
void cancelPendingUpdate() noexcept
GenericScopedLock< CriticalSection > ScopedLockType
GenericScopedUnlock< CriticalSection > ScopedUnlockType
bool wait(int timeOutMilliseconds) const
bool threadShouldExit() const
bool stopThread(int timeOutMilliseconds)
void signalThreadShouldExit()
bool isThreadRunning() const
static uint32 getMillisecondCounter() noexcept
void stopTimer() noexcept
void startTimerHz(int timerFrequencyHz) noexcept
static void JUCE_CALLTYPE callPendingTimersSynchronously()
static void JUCE_CALLTYPE callAfterDelay(int milliseconds, std::function< void()> functionToCall)
void startTimer(int intervalInMilliseconds) noexcept