]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/generic/timer.cpp
fixing reentrancy which happened in tests, bringing client coordinates origins in...
[wxWidgets.git] / src / generic / timer.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/generic/timer.cpp
3// Purpose: wxTimer implementation
4// Author: Vaclav Slavik
5// Id: $Id$
6// Copyright: (c) Vaclav Slavik
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
13#ifdef __BORLANDC__
14 #pragma hdrstop
15#endif
16
17// ----------------------------------------------------------------------------
18// NB: when using generic wxTimer implementation in your port, you *must* call
19// wxTimer::NotifyTimers() often enough. The ideal place for this
20// is in wxEventLoop::Dispatch().
21// ----------------------------------------------------------------------------
22
23#if wxUSE_TIMER
24
25#ifndef WX_PRECOMP
26 #include "wx/log.h"
27 #include "wx/module.h"
28#endif
29
30#include "wx/apptrait.h"
31#include "wx/generic/private/timer.h"
32
33// ----------------------------------------------------------------------------
34// Time input function
35// ----------------------------------------------------------------------------
36
37#define GetMillisecondsTime wxGetLocalTimeMillis
38
39typedef wxLongLong wxTimerTick_t;
40
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
48
49inline bool wxTickGreaterEqual(wxTimerTick_t x, wxTimerTick_t y)
50{
51 return x >= y;
52}
53
54// ----------------------------------------------------------------------------
55// helper structures and wxTimerScheduler
56// ----------------------------------------------------------------------------
57
58class wxTimerDesc
59{
60public:
61 wxTimerDesc(wxGenericTimerImpl *t) :
62 timer(t), running(false), next(NULL), prev(NULL),
63 shotTime(0), deleteFlag(NULL) {}
64
65 wxGenericTimerImpl *timer;
66 bool running;
67 wxTimerDesc *next, *prev;
68 wxTimerTick_t shotTime;
69 volatile bool *deleteFlag; // see comment in ~wxTimer
70};
71
72class wxTimerScheduler
73{
74public:
75 wxTimerScheduler() : m_timers(NULL) {}
76
77 void QueueTimer(wxTimerDesc *desc, wxTimerTick_t when = 0);
78 void RemoveTimer(wxTimerDesc *desc);
79 void NotifyTimers();
80
81private:
82 wxTimerDesc *m_timers;
83};
84
85void wxTimerScheduler::QueueTimer(wxTimerDesc *desc, wxTimerTick_t when)
86{
87 if ( desc->running )
88 return; // already scheduled
89
90 if ( when == 0 )
91 when = GetMillisecondsTime() + desc->timer->GetInterval();
92 desc->shotTime = when;
93 desc->running = true;
94
95 wxLogTrace( wxT("timer"),
96 wxT("queued timer %p at tick %") wxTimerTickFmtSpec,
97 desc->timer, wxTimerTickPrintfArg(when));
98
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{
118 desc->running = false;
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 {
132 bool oneShot;
133 volatile bool timerDeleted;
134 wxTimerTick_t now = GetMillisecondsTime();
135
136 for ( wxTimerDesc *desc = m_timers; desc; desc = desc->next )
137 {
138 if ( desc->running && wxTickGreaterEqual(now, desc->shotTime) )
139 {
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 }
159 else
160 {
161 desc = m_timers;
162 if (!desc)
163 break;
164 }
165 }
166 }
167 }
168}
169
170
171// ----------------------------------------------------------------------------
172// wxTimer
173// ----------------------------------------------------------------------------
174
175wxTimerScheduler *gs_scheduler = NULL;
176
177void wxGenericTimerImpl::Init()
178{
179 if ( !gs_scheduler )
180 gs_scheduler = new wxTimerScheduler;
181 m_desc = new wxTimerDesc(this);
182}
183
184wxGenericTimerImpl::~wxGenericTimerImpl()
185{
186 wxLogTrace( wxT("timer"), wxT("destroying timer %p..."), this);
187 if ( IsRunning() )
188 Stop();
189
190 // NB: this is a hack: wxTimerScheduler must have some way of knowing
191 // that wxTimer object was deleted under its hands -- this may
192 // happen if somebody is really nasty and deletes the timer
193 // from wxTimer::Notify()
194 if ( m_desc->deleteFlag != NULL )
195 *m_desc->deleteFlag = true;
196
197 delete m_desc;
198 wxLogTrace( wxT("timer"), wxT(" ...done destroying timer %p..."), this);
199}
200
201bool wxGenericTimerImpl::IsRunning() const
202{
203 return m_desc->running;
204}
205
206bool wxGenericTimerImpl::Start(int millisecs, bool oneShot)
207{
208 wxLogTrace( wxT("timer"), wxT("started timer %p: %i ms, oneshot=%i"),
209 this, millisecs, oneShot);
210
211 if ( !wxTimerImpl::Start(millisecs, oneShot) )
212 return false;
213
214 gs_scheduler->QueueTimer(m_desc);
215 return true;
216}
217
218void wxGenericTimerImpl::Stop()
219{
220 if ( !m_desc->running ) return;
221
222 gs_scheduler->RemoveTimer(m_desc);
223}
224
225/*static*/ void wxGenericTimerImpl::NotifyTimers()
226{
227 if ( gs_scheduler )
228 gs_scheduler->NotifyTimers();
229}
230
231
232
233// A module to deallocate memory properly:
234class wxTimerModule: public wxModule
235{
236DECLARE_DYNAMIC_CLASS(wxTimerModule)
237public:
238 wxTimerModule() {}
239 bool OnInit() { return true; }
240 void OnExit() { wxDELETE(gs_scheduler); }
241};
242
243IMPLEMENT_DYNAMIC_CLASS(wxTimerModule, wxModule)
244
245// ----------------------------------------------------------------------------
246// wxGUIAppTraits
247// ----------------------------------------------------------------------------
248
249wxTimerImpl *wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
250{
251 return new wxGenericTimerImpl(timer);
252}
253
254
255#endif //wxUSE_TIMER