]> git.saurik.com Git - wxWidgets.git/blame - src/generic/timer.cpp
moved fix
[wxWidgets.git] / src / generic / timer.cpp
CommitLineData
32b8ec41 1/////////////////////////////////////////////////////////////////////////////
1acd70f9 2// Name: mgl/timer.cpp
32b8ec41 3// Purpose: wxTimer implementation
1acd70f9 4// Author: Vaclav Slavik
32b8ec41 5// Id: $Id$
c41c20a5 6// Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com)
32b8ec41
VZ
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
32b8ec41
VZ
10#ifdef __GNUG__
11#pragma implementation "timer.h"
12#endif
13
a246f95e
VS
14// For compilers that support precompilation, includes "wx.h".
15#include "wx/wxprec.h"
16
17#ifdef __BORLANDC__
18 #pragma hdrstop
19#endif
20
a0cb0ba5
VS
21// ----------------------------------------------------------------------------
22// NB: when using generic wxTimer implementation in your port, you *must* call
23// wxTimer::NotifyTimers() often enough. The ideal place for this
24// is in wxEventLoop::Dispatch().
25// ----------------------------------------------------------------------------
26
32b8ec41
VZ
27#include "wx/timer.h"
28
1acd70f9
VS
29#if wxUSE_TIMER
30
88f2a771 31#include "wx/log.h"
0e4b9976 32#include "wx/module.h"
1acd70f9 33
a0cb0ba5
VS
34// ----------------------------------------------------------------------------
35// Time input function
36// ----------------------------------------------------------------------------
37
38#ifdef __WXMGL__
39 // We take advantage of wxMGL's _EVT_getTicks because it is faster
40 // (especially under MS-DOS!) and more precise than wxGetLocalTimeMillis
41 // if we are unlucky and the latter combines information from two sources.
42 #include "wx/mgl/private.h"
43 extern "C" ulong _EVT_getTicks();
44 #define GetMillisecondsTime() _EVT_getTicks()
45#else
4cae9a20
JS
46// #define GetMillisecondsTime() wxGetLocalTimeMillis().ToLong()
47 // Suppresses the debug warning in ToLong. FIXME: check
48 // that we don't drastically lose precision
49 #define GetMillisecondsTime() (unsigned long) wxGetLocalTimeMillis().GetValue()
a0cb0ba5 50#endif
1acd70f9
VS
51
52// ----------------------------------------------------------------------------
53// helper structures and wxTimerScheduler
54// ----------------------------------------------------------------------------
55
56class wxTimerDesc
57{
58public:
0e4b9976
VS
59 wxTimerDesc(wxTimer *t) :
60 timer(t), running(FALSE), next(NULL), prev(NULL),
61 shotTime(0), deleteFlag(NULL) {}
1acd70f9
VS
62
63 wxTimer *timer;
64 bool running;
65 wxTimerDesc *next, *prev;
0e4b9976
VS
66 unsigned long shotTime;
67 volatile bool *deleteFlag; // see comment in ~wxTimer
1acd70f9
VS
68};
69
70class wxTimerScheduler
71{
72public:
73 wxTimerScheduler() : m_timers(NULL) {}
74
75 void QueueTimer(wxTimerDesc *desc, unsigned long when = 0);
76 void RemoveTimer(wxTimerDesc *desc);
77 void NotifyTimers();
78
79private:
80 wxTimerDesc *m_timers;
81};
82
83void wxTimerScheduler::QueueTimer(wxTimerDesc *desc, unsigned long when)
84{
0e4b9976
VS
85 if ( desc->running )
86 return; // already scheduled
87
1acd70f9 88 if ( when == 0 )
a0cb0ba5 89 when = GetMillisecondsTime() + desc->timer->GetInterval();
1acd70f9
VS
90 desc->shotTime = when;
91 desc->running = TRUE;
92
2b5f62a0 93 wxLogTrace( wxT("timer"), wxT("queued timer %p at tick %ld"),
bbcd408a 94 desc->timer, (long) when);
88f2a771 95
1acd70f9
VS
96 if ( m_timers )
97 {
98 wxTimerDesc *d = m_timers;
99 while ( d->next && d->next->shotTime < when ) d = d->next;
100 desc->next = d->next;
101 desc->prev = d;
102 if ( d->next )
103 d->next->prev = desc;
104 d->next = desc;
105 }
106 else
107 {
108 m_timers = desc;
109 desc->prev = desc->next = NULL;
110 }
111}
112
113void wxTimerScheduler::RemoveTimer(wxTimerDesc *desc)
114{
115 desc->running = FALSE;
116 if ( desc == m_timers )
117 m_timers = desc->next;
118 if ( desc->prev )
119 desc->prev->next = desc->next;
120 if ( desc->next )
121 desc->next->prev = desc->prev;
122 desc->prev = desc->next = NULL;
123}
124
125void wxTimerScheduler::NotifyTimers()
126{
127 if ( m_timers )
128 {
0e4b9976
VS
129 bool oneShot;
130 volatile bool timerDeleted;
a0cb0ba5 131 unsigned long now = GetMillisecondsTime();
1acd70f9 132 wxTimerDesc *desc;
88f2a771 133
1acd70f9
VS
134 while ( m_timers && m_timers->shotTime <= now )
135 {
136 desc = m_timers;
0e4b9976 137 oneShot = desc->timer->IsOneShot();
1acd70f9 138 RemoveTimer(desc);
88f2a771 139
0e4b9976
VS
140 timerDeleted = FALSE;
141 desc->deleteFlag = &timerDeleted;
88f2a771 142 desc->timer->Notify();
0e4b9976
VS
143
144 if ( !timerDeleted )
1acd70f9 145 {
2b5f62a0 146 wxLogTrace( wxT("timer"), wxT("notified timer %p sheduled for %ld"),
bbcd408a 147 desc->timer, (long) desc->shotTime);
0e4b9976
VS
148
149 desc->deleteFlag = NULL;
150 if ( !oneShot )
151 QueueTimer(desc, now + desc->timer->GetInterval());
1acd70f9
VS
152 }
153 }
154 }
155}
156
157
32b8ec41
VZ
158// ----------------------------------------------------------------------------
159// wxTimer
160// ----------------------------------------------------------------------------
161
162IMPLEMENT_ABSTRACT_CLASS(wxTimer,wxObject)
163
0e4b9976 164wxTimerScheduler *gs_scheduler = NULL;
1acd70f9
VS
165
166void wxTimer::Init()
167{
0e4b9976
VS
168 if ( !gs_scheduler )
169 gs_scheduler = new wxTimerScheduler;
1acd70f9
VS
170 m_desc = new wxTimerDesc(this);
171}
172
173wxTimer::~wxTimer()
174{
2b5f62a0 175 wxLogTrace( wxT("timer"), wxT("destroying timer %p..."), this);
1acd70f9
VS
176 if ( IsRunning() )
177 Stop();
178
0e4b9976
VS
179 // NB: this is a hack: wxTimerScheduler must have some way of knowing
180 // that wxTimer object was deleted under its hands -- this may
181 // happen if somebody is really nasty and deletes the timer
182 // from wxTimer::Notify()
183 if ( m_desc->deleteFlag != NULL )
184 *m_desc->deleteFlag = TRUE;
185
1acd70f9 186 delete m_desc;
2b5f62a0 187 wxLogTrace( wxT("timer"), wxT(" ...done destroying timer %p..."), this);
1acd70f9
VS
188}
189
190bool wxTimer::IsRunning() const
191{
192 return m_desc->running;
193}
194
195bool wxTimer::Start(int millisecs, bool oneShot)
196{
2b5f62a0 197 wxLogTrace( wxT("timer"), wxT("started timer %p: %i ms, oneshot=%i"),
88f2a771
VS
198 this, millisecs, oneShot);
199
1acd70f9
VS
200 if ( !wxTimerBase::Start(millisecs, oneShot) )
201 return FALSE;
202
0e4b9976 203 gs_scheduler->QueueTimer(m_desc);
1acd70f9
VS
204 return TRUE;
205}
206
207void wxTimer::Stop()
208{
209 if ( !m_desc->running ) return;
210
0e4b9976 211 gs_scheduler->RemoveTimer(m_desc);
1acd70f9
VS
212}
213
214/*static*/ void wxTimer::NotifyTimers()
215{
0e4b9976
VS
216 if ( gs_scheduler )
217 gs_scheduler->NotifyTimers();
1acd70f9
VS
218}
219
0e4b9976
VS
220
221
222// A module to deallocate memory properly:
223class wxTimerModule: public wxModule
224{
225DECLARE_DYNAMIC_CLASS(wxTimerModule)
226public:
227 wxTimerModule() {}
228 bool OnInit() { return TRUE; }
229 void OnExit() { delete gs_scheduler; gs_scheduler = NULL; }
230};
231
232IMPLEMENT_DYNAMIC_CLASS(wxTimerModule, wxModule)
233
234
1acd70f9 235#endif //wxUSE_TIMER