44 jassert (instance ==
this || instance ==
nullptr);
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();
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
331 bool wasStopped = (timerPeriodMs == 0);
332 timerPeriodMs = jmax (1, interval);
335 TimerThread::add (
this);
337 TimerThread::resetCounter (
this);
342 if (timerFrequencyHz > 0)
343 startTimer (1000 / timerFrequencyHz);
352 if (timerPeriodMs > 0)
354 TimerThread::remove (
this);
361 if (TimerThread::instance !=
nullptr)
362 TimerThread::instance->callTimersSynchronously();
367 LambdaInvoker (
int milliseconds, std::function<
void()> f) : function (f)
379 std::function<void()> function;
Has a callback method that is triggered asynchronously.
void triggerAsyncUpdate()
Causes the callback to be triggered at a later time.
void cancelPendingUpdate() noexcept
This will stop any pending updates from happening.
GenericScopedLock< CriticalSection > ScopedLockType
Provides the type of scoped lock to use with a CriticalSection.
GenericScopedUnlock< CriticalSection > ScopedUnlockType
Provides the type of scoped unlocker to use with a CriticalSection.
Classes derived from this will be automatically deleted when the application exits.
Automatically locks and unlocks a mutex object.
A smart-pointer class which points to a reference-counted object.
void startThread()
Starts the thread running.
bool wait(int timeOutMilliseconds) const
Suspends the execution of this thread until either the specified timeout period has elapsed,...
Thread(const String &threadName, size_t threadStackSize=0)
Creates a thread.
bool threadShouldExit() const
Checks whether the thread has been told to stop running.
bool stopThread(int timeOutMilliseconds)
Attempts to stop the thread running.
void notify() const
Wakes up the thread.
void signalThreadShouldExit()
Sets a flag to tell the thread it should stop.
bool isThreadRunning() const
Returns true if the thread is currently active.
static uint32 getMillisecondCounter() noexcept
Returns the number of millisecs since a fixed event (usually system startup).
void run() override
Must be implemented to perform the thread's actual code.
Makes repeated callbacks to a virtual method at a specified time interval.
virtual ~Timer()
Destructor.
void stopTimer() noexcept
Stops the timer.
Timer() noexcept
Creates a Timer.
void startTimerHz(int timerFrequencyHz) noexcept
Starts the timer with an interval specified in Hertz.
static void JUCE_CALLTYPE callPendingTimersSynchronously()
For internal use only: invokes any timers that need callbacks.
static void JUCE_CALLTYPE callAfterDelay(int milliseconds, std::function< void()> functionToCall)
Invokes a lambda after a given number of milliseconds.
void startTimer(int intervalInMilliseconds) noexcept
Starts the timer and sets the length of interval required.
bool wait(int timeOutMilliseconds=-1) const
Suspends the calling thread until the event has been signalled.
void signal() const
Wakes up any threads that are currently waiting on this object.
void timerCallback() override
The user-defined callback routine that actually gets called periodically.