]> git.saurik.com Git - wxWidgets.git/blame - src/generic/timer.cpp
fixing reentrancy which happened in tests, bringing client coordinates origins in...
[wxWidgets.git] / src / generic / timer.cpp
CommitLineData
32b8ec41 1/////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/generic/timer.cpp
32b8ec41 3// Purpose: wxTimer implementation
1acd70f9 4// Author: Vaclav Slavik
32b8ec41 5// Id: $Id$
6d89ddef 6// Copyright: (c) Vaclav Slavik
65571936 7// Licence: wxWindows licence
32b8ec41
VZ
8/////////////////////////////////////////////////////////////////////////////
9
a246f95e
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
13#ifdef __BORLANDC__
14 #pragma hdrstop
15#endif
16
a0cb0ba5 17// ----------------------------------------------------------------------------
ca65c044
WS
18// NB: when using generic wxTimer implementation in your port, you *must* call
19// wxTimer::NotifyTimers() often enough. The ideal place for this
a0cb0ba5
VS
20// is in wxEventLoop::Dispatch().
21// ----------------------------------------------------------------------------
22
e4db172a
WS
23#if wxUSE_TIMER
24
e4db172a
WS
25#ifndef WX_PRECOMP
26 #include "wx/log.h"
02761f6c 27 #include "wx/module.h"
e4db172a 28#endif
1acd70f9 29
c2ca375c
VZ
30#include "wx/apptrait.h"
31#include "wx/generic/private/timer.h"
32
a0cb0ba5
VS
33// ----------------------------------------------------------------------------
34// Time input function
35// ----------------------------------------------------------------------------
36
0e1f8ea4 37#define GetMillisecondsTime wxGetLocalTimeMillis
9750481f 38
0e1f8ea4 39typedef wxLongLong wxTimerTick_t;
5ed08e5b 40
0e1f8ea4
VZ
41#if wxUSE_LONGLONG_WX
42 #define wxTimerTickFmtSpec wxLongLongFmtSpec "d"
43 #define wxTimerTickPrintfArg(tt) (tt.GetValue())
44#else // using native wxLongLong
45 #define wxTimerTickFmtSpec wxT("s")
46 #define wxTimerTickPrintfArg(tt) (tt.ToString().c_str())
47#endif // wx/native long long
9814d926 48
0e1f8ea4
VZ
49inline bool wxTickGreaterEqual(wxTimerTick_t x, wxTimerTick_t y)
50{
51 return x >= y;
52}
1acd70f9
VS
53
54// ----------------------------------------------------------------------------
55// helper structures and wxTimerScheduler
56// ----------------------------------------------------------------------------
57
58class wxTimerDesc
59{
60public:
c2ca375c 61 wxTimerDesc(wxGenericTimerImpl *t) :
ca65c044 62 timer(t), running(false), next(NULL), prev(NULL),
0e4b9976 63 shotTime(0), deleteFlag(NULL) {}
1acd70f9 64
c2ca375c
VZ
65 wxGenericTimerImpl *timer;
66 bool running;
67 wxTimerDesc *next, *prev;
68 wxTimerTick_t shotTime;
69 volatile bool *deleteFlag; // see comment in ~wxTimer
1acd70f9
VS
70};
71
72class wxTimerScheduler
73{
74public:
75 wxTimerScheduler() : m_timers(NULL) {}
76
9750481f 77 void QueueTimer(wxTimerDesc *desc, wxTimerTick_t when = 0);
1acd70f9
VS
78 void RemoveTimer(wxTimerDesc *desc);
79 void NotifyTimers();
ca65c044 80
1acd70f9
VS
81private:
82 wxTimerDesc *m_timers;
83};
84
9750481f 85void wxTimerScheduler::QueueTimer(wxTimerDesc *desc, wxTimerTick_t when)
1acd70f9 86{
0e4b9976
VS
87 if ( desc->running )
88 return; // already scheduled
ca65c044 89
1acd70f9 90 if ( when == 0 )
a0cb0ba5 91 when = GetMillisecondsTime() + desc->timer->GetInterval();
1acd70f9 92 desc->shotTime = when;
ca65c044 93 desc->running = true;
1acd70f9 94
ee9768c9 95 wxLogTrace( wxT("timer"),
ca65c044 96 wxT("queued timer %p at tick %") wxTimerTickFmtSpec,
5ed08e5b 97 desc->timer, wxTimerTickPrintfArg(when));
88f2a771 98
1acd70f9
VS
99 if ( m_timers )
100 {
101 wxTimerDesc *d = m_timers;
102 while ( d->next && d->next->shotTime < when ) d = d->next;
103 desc->next = d->next;
104 desc->prev = d;
105 if ( d->next )
106 d->next->prev = desc;
107 d->next = desc;
108 }
109 else
110 {
111 m_timers = desc;
112 desc->prev = desc->next = NULL;
113 }
114}
115
116void wxTimerScheduler::RemoveTimer(wxTimerDesc *desc)
117{
ca65c044 118 desc->running = false;
1acd70f9
VS
119 if ( desc == m_timers )
120 m_timers = desc->next;
121 if ( desc->prev )
122 desc->prev->next = desc->next;
123 if ( desc->next )
124 desc->next->prev = desc->prev;
125 desc->prev = desc->next = NULL;
126}
127
128void wxTimerScheduler::NotifyTimers()
129{
130 if ( m_timers )
131 {
0e4b9976
VS
132 bool oneShot;
133 volatile bool timerDeleted;
9750481f 134 wxTimerTick_t now = GetMillisecondsTime();
88f2a771 135
c3732409 136 for ( wxTimerDesc *desc = m_timers; desc; desc = desc->next )
1acd70f9 137 {
9814d926 138 if ( desc->running && wxTickGreaterEqual(now, desc->shotTime) )
1acd70f9 139 {
c3732409
VZ
140 oneShot = desc->timer->IsOneShot();
141 RemoveTimer(desc);
142
143 timerDeleted = false;
144 desc->deleteFlag = &timerDeleted;
145 desc->timer->Notify();
146
147 if ( !timerDeleted )
148 {
149 wxLogTrace( wxT("timer"),
150 wxT("notified timer %p sheduled for %")
151 wxTimerTickFmtSpec,
152 desc->timer,
153 wxTimerTickPrintfArg(desc->shotTime) );
154
155 desc->deleteFlag = NULL;
156 if ( !oneShot )
157 QueueTimer(desc, now + desc->timer->GetInterval());
158 }
925fcf5f 159 else
dd7230ab 160 {
925fcf5f 161 desc = m_timers;
dd7230ab
JS
162 if (!desc)
163 break;
164 }
1acd70f9
VS
165 }
166 }
167 }
168}
169
170
32b8ec41
VZ
171// ----------------------------------------------------------------------------
172// wxTimer
173// ----------------------------------------------------------------------------
174
0e4b9976 175wxTimerScheduler *gs_scheduler = NULL;
1acd70f9 176
c2ca375c 177void wxGenericTimerImpl::Init()
1acd70f9 178{
0e4b9976
VS
179 if ( !gs_scheduler )
180 gs_scheduler = new wxTimerScheduler;
1acd70f9
VS
181 m_desc = new wxTimerDesc(this);
182}
183
c2ca375c 184wxGenericTimerImpl::~wxGenericTimerImpl()
1acd70f9 185{
2b5f62a0 186 wxLogTrace( wxT("timer"), wxT("destroying timer %p..."), this);
1acd70f9
VS
187 if ( IsRunning() )
188 Stop();
189
0e4b9976 190 // NB: this is a hack: wxTimerScheduler must have some way of knowing
ca65c044 191 // that wxTimer object was deleted under its hands -- this may
0e4b9976
VS
192 // happen if somebody is really nasty and deletes the timer
193 // from wxTimer::Notify()
194 if ( m_desc->deleteFlag != NULL )
ca65c044 195 *m_desc->deleteFlag = true;
0e4b9976 196
1acd70f9 197 delete m_desc;
2b5f62a0 198 wxLogTrace( wxT("timer"), wxT(" ...done destroying timer %p..."), this);
1acd70f9
VS
199}
200
c2ca375c 201bool wxGenericTimerImpl::IsRunning() const
1acd70f9
VS
202{
203 return m_desc->running;
204}
205
c2ca375c 206bool wxGenericTimerImpl::Start(int millisecs, bool oneShot)
1acd70f9 207{
ca65c044 208 wxLogTrace( wxT("timer"), wxT("started timer %p: %i ms, oneshot=%i"),
88f2a771
VS
209 this, millisecs, oneShot);
210
c2ca375c
VZ
211 if ( !wxTimerImpl::Start(millisecs, oneShot) )
212 return false;
ca65c044 213
0e4b9976 214 gs_scheduler->QueueTimer(m_desc);
ca65c044 215 return true;
1acd70f9
VS
216}
217
c2ca375c 218void wxGenericTimerImpl::Stop()
1acd70f9
VS
219{
220 if ( !m_desc->running ) return;
ca65c044 221
0e4b9976 222 gs_scheduler->RemoveTimer(m_desc);
1acd70f9
VS
223}
224
c2ca375c 225/*static*/ void wxGenericTimerImpl::NotifyTimers()
1acd70f9 226{
0e4b9976
VS
227 if ( gs_scheduler )
228 gs_scheduler->NotifyTimers();
1acd70f9
VS
229}
230
0e4b9976
VS
231
232
233// A module to deallocate memory properly:
234class wxTimerModule: public wxModule
235{
236DECLARE_DYNAMIC_CLASS(wxTimerModule)
237public:
238 wxTimerModule() {}
ca65c044 239 bool OnInit() { return true; }
5276b0a5 240 void OnExit() { wxDELETE(gs_scheduler); }
0e4b9976
VS
241};
242
243IMPLEMENT_DYNAMIC_CLASS(wxTimerModule, wxModule)
244
c2ca375c
VZ
245// ----------------------------------------------------------------------------
246// wxGUIAppTraits
247// ----------------------------------------------------------------------------
248
249wxTimerImpl *wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
250{
251 return new wxGenericTimerImpl(timer);
252}
253
0e4b9976 254
1acd70f9 255#endif //wxUSE_TIMER