1
/////////////////////////////////////////////////////////////////////////////
2
// Name: src/generic/timer.cpp
3
// Purpose: wxTimer implementation
4
// Author: Vaclav Slavik
5
// Copyright: (c) Vaclav Slavik
6
// Licence: wxWindows licence
7
/////////////////////////////////////////////////////////////////////////////
9
// For compilers that support precompilation, includes "wx.h".
10
#include "wx/wxprec.h"
16
// ----------------------------------------------------------------------------
17
// NB: when using generic wxTimer implementation in your port, you *must* call
18
// wxTimer::NotifyTimers() often enough. The ideal place for this
19
// is in wxEventLoop::Dispatch().
20
// ----------------------------------------------------------------------------
26
#include "wx/module.h"
29
#include "wx/apptrait.h"
30
#include "wx/generic/private/timer.h"
32
// ----------------------------------------------------------------------------
33
// Time input function
34
// ----------------------------------------------------------------------------
36
#define GetMillisecondsTime wxGetLocalTimeMillis
38
typedef wxLongLong wxTimerTick_t;
41
#define wxTimerTickFmtSpec wxLongLongFmtSpec "d"
42
#define wxTimerTickPrintfArg(tt) (tt.GetValue())
43
#else // using native wxLongLong
44
#define wxTimerTickFmtSpec wxT("s")
45
#define wxTimerTickPrintfArg(tt) (tt.ToString().c_str())
46
#endif // wx/native long long
48
inline bool wxTickGreaterEqual(wxTimerTick_t x, wxTimerTick_t y)
53
// ----------------------------------------------------------------------------
54
// helper structures and wxTimerScheduler
55
// ----------------------------------------------------------------------------
60
wxTimerDesc(wxGenericTimerImpl *t) :
61
timer(t), running(false), next(NULL), prev(NULL),
62
shotTime(0), deleteFlag(NULL) {}
64
wxGenericTimerImpl *timer;
66
wxTimerDesc *next, *prev;
67
wxTimerTick_t shotTime;
68
volatile bool *deleteFlag; // see comment in ~wxTimer
71
class wxTimerScheduler
74
wxTimerScheduler() : m_timers(NULL) {}
76
void QueueTimer(wxTimerDesc *desc, wxTimerTick_t when = 0);
77
void RemoveTimer(wxTimerDesc *desc);
81
wxTimerDesc *m_timers;
84
void wxTimerScheduler::QueueTimer(wxTimerDesc *desc, wxTimerTick_t when)
87
return; // already scheduled
90
when = GetMillisecondsTime() + desc->timer->GetInterval();
91
desc->shotTime = when;
94
wxLogTrace( wxT("timer"),
95
wxT("queued timer %p at tick %") wxTimerTickFmtSpec,
96
desc->timer, wxTimerTickPrintfArg(when));
100
wxTimerDesc *d = m_timers;
101
while ( d->next && d->next->shotTime < when ) d = d->next;
102
desc->next = d->next;
105
d->next->prev = desc;
111
desc->prev = desc->next = NULL;
115
void wxTimerScheduler::RemoveTimer(wxTimerDesc *desc)
117
desc->running = false;
118
if ( desc == m_timers )
119
m_timers = desc->next;
121
desc->prev->next = desc->next;
123
desc->next->prev = desc->prev;
124
desc->prev = desc->next = NULL;
127
void wxTimerScheduler::NotifyTimers()
132
volatile bool timerDeleted;
133
wxTimerTick_t now = GetMillisecondsTime();
135
for ( wxTimerDesc *desc = m_timers; desc; desc = desc->next )
137
if ( desc->running && wxTickGreaterEqual(now, desc->shotTime) )
139
oneShot = desc->timer->IsOneShot();
142
timerDeleted = false;
143
desc->deleteFlag = &timerDeleted;
144
desc->timer->Notify();
148
wxLogTrace( wxT("timer"),
149
wxT("notified timer %p sheduled for %")
152
wxTimerTickPrintfArg(desc->shotTime) );
154
desc->deleteFlag = NULL;
156
QueueTimer(desc, now + desc->timer->GetInterval());
170
// ----------------------------------------------------------------------------
172
// ----------------------------------------------------------------------------
174
wxTimerScheduler *gs_scheduler = NULL;
176
void wxGenericTimerImpl::Init()
179
gs_scheduler = new wxTimerScheduler;
180
m_desc = new wxTimerDesc(this);
183
wxGenericTimerImpl::~wxGenericTimerImpl()
185
wxLogTrace( wxT("timer"), wxT("destroying timer %p..."), this);
189
// NB: this is a hack: wxTimerScheduler must have some way of knowing
190
// that wxTimer object was deleted under its hands -- this may
191
// happen if somebody is really nasty and deletes the timer
192
// from wxTimer::Notify()
193
if ( m_desc->deleteFlag != NULL )
194
*m_desc->deleteFlag = true;
197
wxLogTrace( wxT("timer"), wxT(" ...done destroying timer %p..."), this);
200
bool wxGenericTimerImpl::IsRunning() const
202
return m_desc->running;
205
bool wxGenericTimerImpl::Start(int millisecs, bool oneShot)
207
wxLogTrace( wxT("timer"), wxT("started timer %p: %i ms, oneshot=%i"),
208
this, millisecs, oneShot);
210
if ( !wxTimerImpl::Start(millisecs, oneShot) )
213
gs_scheduler->QueueTimer(m_desc);
217
void wxGenericTimerImpl::Stop()
219
if ( !m_desc->running ) return;
221
gs_scheduler->RemoveTimer(m_desc);
224
/*static*/ void wxGenericTimerImpl::NotifyTimers()
227
gs_scheduler->NotifyTimers();
232
// A module to deallocate memory properly:
233
class wxTimerModule: public wxModule
235
DECLARE_DYNAMIC_CLASS(wxTimerModule)
238
bool OnInit() { return true; }
239
void OnExit() { wxDELETE(gs_scheduler); }
242
IMPLEMENT_DYNAMIC_CLASS(wxTimerModule, wxModule)
244
// ----------------------------------------------------------------------------
246
// ----------------------------------------------------------------------------
248
wxTimerImpl *wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
250
return new wxGenericTimerImpl(timer);