/** * \brief Executes the callback of a timer. * * Then, if the callback returns \c true, the timer is rescheduled, * otherwise it is discarded. * * Does nothing if the timer is already finished. * * \param timer The timer to execute. */ void LuaContext::do_timer_callback(const TimerPtr& timer) { Debug::check_assertion(timer->is_finished(), "This timer is still running"); auto it = timers.find(timer); if (it != timers.end() && !it->second.callback_ref.is_empty()) { ScopedLuaRef& callback_ref = it->second.callback_ref; push_ref(l, callback_ref); const bool success = call_function(0, 1, "timer callback"); bool repeat = false; if (success) { repeat = lua_isboolean(l, -1) && lua_toboolean(l, -1); lua_pop(l, 1); } if (repeat) { // The callback returned true: reschedule the timer. timer->set_expiration_date(timer->get_expiration_date() + timer->get_initial_duration()); if (timer->is_finished()) { // Already finished: this is possible if the duration is smaller than // the main loop stepsize. do_timer_callback(timer); } } else { callback_ref.clear(); timers_to_remove.push_back(timer); } } }
/** * \brief Executes the callback of a timer. * * Then, if the callback returns \c true, the timer is rescheduled, * otherwise it is discarded. * * Does nothing if the timer is already finished. * * \param timer The timer to execute. */ void LuaContext::do_timer_callback(Timer& timer) { Debug::check_assertion(timer.is_finished(), "This timer is still running"); const std::map<Timer*, LuaTimerData>::iterator it = timers.find(&timer); if (it != timers.end() && it->second.callback_ref != LUA_REFNIL) { const int callback_ref = it->second.callback_ref; push_callback(callback_ref); const bool success = call_function(0, 1, "timer callback"); bool repeat = false; if (success) { repeat = lua_isboolean(l, -1) && lua_toboolean(l, -1); lua_pop(l, 1); } if (repeat) { // The callback returned true: reschedule the timer. timer.set_expiration_date(timer.get_expiration_date() + timer.get_initial_duration()); if (timer.is_finished()) { // Already finished: this is possible if the duration is smaller than // the main loop stepsize. do_timer_callback(timer); } } else { cancel_callback(callback_ref); it->second.callback_ref = LUA_REFNIL; timers_to_remove.push_back(&timer); } } }
/** * \brief Updates all timers currently running for this script. */ void LuaContext::update_timers() { // Update all timers. for (const auto& kvp: timers) { const TimerPtr& timer = kvp.first; const ScopedLuaRef& callback_ref = kvp.second.callback_ref; if (!callback_ref.is_empty()) { // The timer is not being removed: update it. timer->update(); if (timer->is_finished()) { do_timer_callback(timer); } } } // Destroy the ones that should be removed. for (const TimerPtr& timer: timers_to_remove) { const auto& it = timers.find(timer); if (it != timers.end()) { timers.erase(it); Debug::check_assertion(timers.find(timer) == timers.end(), "Failed to remove timer"); } } timers_to_remove.clear(); }
/** * \brief Updates all timers currently running for this script. */ void LuaContext::update_timers() { // Update all timers. std::map<Timer*, LuaTimerData>::iterator it; for (it = timers.begin(); it != timers.end(); ++it) { Timer* timer = it->first; int callback_ref = it->second.callback_ref; if (callback_ref != LUA_REFNIL) { // The timer is not being removed: update it. timer->update(); if (timer->is_finished()) { do_timer_callback(*timer); } } } // Destroy the ones that should be removed. std::list<Timer*>::iterator it2; for (it2 = timers_to_remove.begin(); it2 != timers_to_remove.end(); ++it2) { Timer* timer = *it2; it = timers.find(timer); if (it != timers.end()) { if (!timer->is_finished()) { cancel_callback(it->second.callback_ref); } timers.erase(it); RefCountable::unref(timer); Debug::check_assertion(timers.find(timer) == timers.end(), "Failed to remove timer"); } } timers_to_remove.clear(); }