Remove wxMGL port.
[wxWidgets.git] / src / generic / timer.cpp
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
39 typedef 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
49 inline bool wxTickGreaterEqual(wxTimerTick_t x, wxTimerTick_t y)
50 {
51 return x >= y;
52 }
53
54 // ----------------------------------------------------------------------------
55 // helper structures and wxTimerScheduler
56 // ----------------------------------------------------------------------------
57
58 class wxTimerDesc
59 {
60 public:
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
72 class wxTimerScheduler
73 {
74 public:
75 wxTimerScheduler() : m_timers(NULL) {}
76
77 void QueueTimer(wxTimerDesc *desc, wxTimerTick_t when = 0);
78 void RemoveTimer(wxTimerDesc *desc);
79 void NotifyTimers();
80
81 private:
82 wxTimerDesc *m_timers;
83 };
84
85 void 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
116 void 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
128 void 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
175 wxTimerScheduler *gs_scheduler = NULL;
176
177 void wxGenericTimerImpl::Init()
178 {
179 if ( !gs_scheduler )
180 gs_scheduler = new wxTimerScheduler;
181 m_desc = new wxTimerDesc(this);
182 }
183
184 wxGenericTimerImpl::~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
201 bool wxGenericTimerImpl::IsRunning() const
202 {
203 return m_desc->running;
204 }
205
206 bool 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
218 void 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:
234 class wxTimerModule: public wxModule
235 {
236 DECLARE_DYNAMIC_CLASS(wxTimerModule)
237 public:
238 wxTimerModule() {}
239 bool OnInit() { return true; }
240 void OnExit() { wxDELETE(gs_scheduler); }
241 };
242
243 IMPLEMENT_DYNAMIC_CLASS(wxTimerModule, wxModule)
244
245 // ----------------------------------------------------------------------------
246 // wxGUIAppTraits
247 // ----------------------------------------------------------------------------
248
249 wxTimerImpl *wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
250 {
251 return new wxGenericTimerImpl(timer);
252 }
253
254
255 #endif //wxUSE_TIMER