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)
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);
163 struct TimerCountdown
169 std::vector<TimerCountdown> timers;
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)
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)
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;
void startTimer(int intervalInMilliseconds) noexcept
Starts the timer and sets the length of interval required.
void stopTimer() noexcept
Stops the timer.
bool stopThread(int timeOutMilliseconds)
Attempts to stop the thread running.
void signal() const
Wakes up any threads that are currently waiting on this object.
Thread(const String &threadName, size_t threadStackSize=0)
Creates a thread.
void signalThreadShouldExit()
Sets a flag to tell the thread it should stop.
void triggerAsyncUpdate()
Causes the callback to be triggered at a later time.
Allows threads to wait for events triggered by other threads.
void run() override
Must be implemented to perform the thread's actual code.
Has a callback method that is triggered asynchronously.
void notify() const
Wakes up the thread.
void cancelPendingUpdate() noexcept
This will stop any pending updates from happening.
static void JUCE_CALLTYPE callPendingTimersSynchronously()
For internal use only: invokes any timers that need callbacks.
bool threadShouldExit() const
Checks whether the thread has been told to stop running.
void startTimerHz(int timerFrequencyHz) noexcept
Starts the timer with an interval specified in Hertz.
bool wait(int timeOutMilliseconds=-1) const
Suspends the calling thread until the event has been signalled.
bool isThreadRunning() const
Returns true if the thread is currently active.
static void JUCE_CALLTYPE callAfterDelay(int milliseconds, std::function< void()> functionToCall)
Invokes a lambda after a given number of milliseconds.
virtual ~Timer()
Destructor.
A smart-pointer class which points to a reference-counted object.
void timerCallback() override
The user-defined callback routine that actually gets called periodically.
Classes derived from this will be automatically deleted when the application exits.
Timer() noexcept
Creates a Timer.
Automatically locks and unlocks a mutex object.
bool wait(int timeOutMilliseconds) const
Suspends the execution of this thread until either the specified timeout period has elapsed...
Makes repeated callbacks to a virtual method at a specified time interval.
Automatically unlocks and re-locks a mutex object.
void startThread()
Starts the thread running.
Internal class used as the base class for all message objects.
static uint32 getMillisecondCounter() noexcept
Returns the number of millisecs since a fixed event (usually system startup).