#include "wx/wxprec.h"
+#if wxUSE_TIMER
+
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/module.h"
#include "wx/event.h"
#endif
+#include "wx/apptrait.h"
#include "wx/longlong.h"
+#include "wx/vector.h"
#include <sys/time.h>
#include <signal.h>
#include "wx/unix/private/timer.h"
#include "wx/listimpl.cpp"
-WX_DEFINE_LIST(wxTimerList);
+WX_DEFINE_LIST(wxTimerList)
// trace mask for the debugging messages used here
#define wxTrace_Timer wxT("timer")
#if wxUSE_LONGLONG
return usec.ToString();
#else // wxUsecClock_t == double
- return wxString::Format(_T("%.0f"), usec);
+ return wxString::Format(wxT("%.0f"), usec);
#endif
}
for ( node = m_timers.begin(); node != m_timers.end(); ++node )
{
wxASSERT_MSG( (*node)->m_timer != s->m_timer,
- _T("adding the same timer twice?") );
+ wxT("adding the same timer twice?") );
if ( (*node)->m_expiration > s->m_expiration )
break;
}
}
- wxFAIL_MSG( _T("removing inexistent timer?") );
+ wxFAIL_MSG( wxT("removing inexistent timer?") );
}
bool wxTimerScheduler::GetNext(wxUsecClock_t *remaining) const
if ( m_timers.empty() )
return false;
- wxCHECK_MSG( remaining, false, _T("NULL pointer") );
+ wxCHECK_MSG( remaining, false, wxT("NULL pointer") );
*remaining = (*m_timers.begin())->m_expiration - wxGetLocalTimeUsec();
if ( *remaining < 0 )
return true;
}
-void wxTimerScheduler::NotifyExpired()
+bool wxTimerScheduler::NotifyExpired()
{
if ( m_timers.empty() )
- return;
+ return false;
const wxUsecClock_t now = wxGetLocalTimeUsec();
- wxTimerList::iterator cur,
- next;
- for ( cur = m_timers.begin(); cur != m_timers.end(); cur = next )
+ typedef wxVector<wxUnixTimerImpl *> TimerImpls;
+ TimerImpls toNotify;
+ for ( wxTimerList::iterator next,
+ cur = m_timers.begin(); cur != m_timers.end(); cur = next )
{
wxTimerSchedule * const s = *cur;
if ( s->m_expiration > now )
wxUnixTimerImpl * const timer = s->m_timer;
if ( timer->IsOneShot() )
{
+ // the timer needs to be stopped but don't call its Stop() from
+ // here as it would attempt to remove the timer from our list and
+ // we had already done it, so we just need to reset its state
+ timer->MarkStopped();
+
// don't need it any more
delete s;
}
else // reschedule the next timer expiration
{
- s->m_expiration += timer->GetInterval()*1000;
+ // always keep the expiration time in the future, i.e. base it on
+ // the current time instead of just offsetting it from the current
+ // expiration time because it could happen that we're late and the
+ // current expiration time is (far) in the past
+ s->m_expiration = now + timer->GetInterval()*1000;
DoAddTimer(s);
}
- // and finally notify the timer
- timer->Notify();
+ // we can't notify the timer from this loop as the timer event handler
+ // could modify m_timers (for example, but not only, by stopping this
+ // timer) which would render our iterators invalid, so do it after the
+ // loop end
+ toNotify.push_back(timer);
+ }
+
+ if ( toNotify.empty() )
+ return false;
+
+ for ( TimerImpls::const_iterator i = toNotify.begin(),
+ end = toNotify.end();
+ i != end;
+ ++i )
+ {
+ (*i)->Notify();
}
+
+ return true;
}
// ============================================================================
wxUnixTimerImpl::~wxUnixTimerImpl()
{
- wxASSERT_MSG( !m_isRunning, _T("must have been stopped before") );
+ wxASSERT_MSG( !m_isRunning, wxT("must have been stopped before") );
}
// ============================================================================
return wxGetLocalTimeMillis() * 1000L;
}
+wxTimerImpl *wxConsoleAppTraits::CreateTimerImpl(wxTimer *timer)
+{
+ return new wxUnixTimerImpl(timer);
+}
+
+#endif // wxUSE_TIMER
+