]> git.saurik.com Git - wxWidgets.git/blob - src/generic/timer.cpp
added wxLocale::IsAvailable() (extended patch 1547191)
[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 #include "wx/timer.h"
26
27 #ifndef WX_PRECOMP
28     #include "wx/log.h"
29     #include "wx/module.h"
30 #endif
31
32 // ----------------------------------------------------------------------------
33 // Time input function
34 // ----------------------------------------------------------------------------
35
36 #ifdef __WXMGL__
37     // We take advantage of wxMGL's _EVT_getTicks because it is faster
38     // (especially under MS-DOS!) and more precise than wxGetLocalTimeMillis
39     // if we are unlucky and the latter combines information from two sources.
40     #include "wx/mgl/private.h"
41     extern "C" ulong _EVT_getTicks();
42     #define GetMillisecondsTime _EVT_getTicks
43
44     typedef ulong wxTimerTick_t;
45
46     #define wxTimerTickFmtSpec _T("lu")
47     #define wxTimerTickPrintfArg(tt) (tt)
48
49     #ifdef __DOS__
50         // Under DOS the MGL timer has a 24hr period, so consider the 12 hours
51         // before y to be 'less' and the the 12 hours after 'greater' modulo
52         // 24 hours.
53         inline bool wxTickGreaterEqual(wxTimerTick_t x, wxTimerTick_t y)
54         {
55             // _EVT_getTicks wraps at 1573040 * 55
56             const wxTimerTick_t modulus = 1573040 * 55;
57             return (2 * modulus + x - y) % modulus < modulus / 2;
58         }
59     #else
60         // If wxTimerTick_t is 32-bits then it'll wrap in around 50 days. So
61         // let the 25 days before y be 'less' and 25 days after be 'greater'.
62         inline bool wxTickGreaterEqual(wxTimerTick_t x, wxTimerTick_t y)
63         {
64             // This code assumes wxTimerTick_t is an unsigned type.
65             // Set half_modulus with top bit set and the rest zeros.
66             const wxTimerTick_t half_modulus = ~((~(wxTimerTick_t)0) >> 1);
67             return x - y < half_modulus;
68         }
69     #endif
70 #else // !__WXMGL__
71     #define GetMillisecondsTime wxGetLocalTimeMillis
72
73     typedef wxLongLong wxTimerTick_t;
74
75     #if wxUSE_LONGLONG_WX
76         #define wxTimerTickFmtSpec wxLongLongFmtSpec _T("d")
77         #define wxTimerTickPrintfArg(tt) (tt.GetValue())
78     #else // using native wxLongLong
79         #define wxTimerTickFmtSpec _T("s")
80         #define wxTimerTickPrintfArg(tt) (tt.ToString().c_str())
81     #endif // wx/native long long
82
83     inline bool wxTickGreaterEqual(wxTimerTick_t x, wxTimerTick_t y)
84     {
85         return x >= y;
86     }
87 #endif // __WXMGL__/!__WXMGL__
88
89 // ----------------------------------------------------------------------------
90 // helper structures and wxTimerScheduler
91 // ----------------------------------------------------------------------------
92
93 class wxTimerDesc
94 {
95 public:
96     wxTimerDesc(wxTimer *t) :
97         timer(t), running(false), next(NULL), prev(NULL),
98         shotTime(0), deleteFlag(NULL) {}
99
100     wxTimer         *timer;
101     bool             running;
102     wxTimerDesc     *next, *prev;
103     wxTimerTick_t    shotTime;
104     volatile bool   *deleteFlag; // see comment in ~wxTimer
105 };
106
107 class wxTimerScheduler
108 {
109 public:
110     wxTimerScheduler() : m_timers(NULL) {}
111
112     void QueueTimer(wxTimerDesc *desc, wxTimerTick_t when = 0);
113     void RemoveTimer(wxTimerDesc *desc);
114     void NotifyTimers();
115
116 private:
117     wxTimerDesc *m_timers;
118 };
119
120 void wxTimerScheduler::QueueTimer(wxTimerDesc *desc, wxTimerTick_t when)
121 {
122     if ( desc->running )
123         return; // already scheduled
124
125     if ( when == 0 )
126         when = GetMillisecondsTime() + desc->timer->GetInterval();
127     desc->shotTime = when;
128     desc->running = true;
129
130     wxLogTrace( wxT("timer"),
131                 wxT("queued timer %p at tick %") wxTimerTickFmtSpec,
132                desc->timer,  wxTimerTickPrintfArg(when));
133
134     if ( m_timers )
135     {
136         wxTimerDesc *d = m_timers;
137         while ( d->next && d->next->shotTime < when ) d = d->next;
138         desc->next = d->next;
139         desc->prev = d;
140         if ( d->next )
141             d->next->prev = desc;
142         d->next = desc;
143     }
144     else
145     {
146         m_timers = desc;
147         desc->prev = desc->next = NULL;
148     }
149 }
150
151 void wxTimerScheduler::RemoveTimer(wxTimerDesc *desc)
152 {
153     desc->running = false;
154     if ( desc == m_timers )
155         m_timers = desc->next;
156     if ( desc->prev )
157         desc->prev->next = desc->next;
158     if ( desc->next )
159         desc->next->prev = desc->prev;
160     desc->prev = desc->next = NULL;
161 }
162
163 void wxTimerScheduler::NotifyTimers()
164 {
165     if ( m_timers )
166     {
167         bool oneShot;
168         volatile bool timerDeleted;
169         wxTimerTick_t now = GetMillisecondsTime();
170
171         for ( wxTimerDesc *desc = m_timers; desc; desc = desc->next )
172         {
173             if ( desc->running && wxTickGreaterEqual(now, desc->shotTime) )
174             {
175                 oneShot = desc->timer->IsOneShot();
176                 RemoveTimer(desc);
177
178                 timerDeleted = false;
179                 desc->deleteFlag = &timerDeleted;
180                 desc->timer->Notify();
181
182                 if ( !timerDeleted )
183                 {
184                     wxLogTrace( wxT("timer"),
185                                 wxT("notified timer %p sheduled for %")
186                                 wxTimerTickFmtSpec,
187                                 desc->timer,
188                                 wxTimerTickPrintfArg(desc->shotTime) );
189
190                     desc->deleteFlag = NULL;
191                     if ( !oneShot )
192                         QueueTimer(desc, now + desc->timer->GetInterval());
193                 }
194                 else
195                 {
196                     desc = m_timers;
197                     if (!desc)
198                         break;
199                 }
200             }
201         }
202     }
203 }
204
205
206 // ----------------------------------------------------------------------------
207 // wxTimer
208 // ----------------------------------------------------------------------------
209
210 IMPLEMENT_ABSTRACT_CLASS(wxTimer, wxEvtHandler)
211
212 wxTimerScheduler *gs_scheduler = NULL;
213
214 void wxTimer::Init()
215 {
216     if ( !gs_scheduler )
217         gs_scheduler = new wxTimerScheduler;
218     m_desc = new wxTimerDesc(this);
219 }
220
221 wxTimer::~wxTimer()
222 {
223     wxLogTrace( wxT("timer"), wxT("destroying timer %p..."), this);
224     if ( IsRunning() )
225         Stop();
226
227     // NB: this is a hack: wxTimerScheduler must have some way of knowing
228     //     that wxTimer object was deleted under its hands -- this may
229     //     happen if somebody is really nasty and deletes the timer
230     //     from wxTimer::Notify()
231     if ( m_desc->deleteFlag != NULL )
232         *m_desc->deleteFlag = true;
233
234     delete m_desc;
235     wxLogTrace( wxT("timer"), wxT("    ...done destroying timer %p..."), this);
236 }
237
238 bool wxTimer::IsRunning() const
239 {
240     return m_desc->running;
241 }
242
243 bool wxTimer::Start(int millisecs, bool oneShot)
244 {
245     wxLogTrace( wxT("timer"), wxT("started timer %p: %i ms, oneshot=%i"),
246                this, millisecs, oneShot);
247
248     if ( !wxTimerBase::Start(millisecs, oneShot) )
249         return false;
250
251     gs_scheduler->QueueTimer(m_desc);
252     return true;
253 }
254
255 void wxTimer::Stop()
256 {
257     if ( !m_desc->running ) return;
258
259     gs_scheduler->RemoveTimer(m_desc);
260 }
261
262 /*static*/ void wxTimer::NotifyTimers()
263 {
264     if ( gs_scheduler )
265         gs_scheduler->NotifyTimers();
266 }
267
268
269
270 // A module to deallocate memory properly:
271 class wxTimerModule: public wxModule
272 {
273 DECLARE_DYNAMIC_CLASS(wxTimerModule)
274 public:
275     wxTimerModule() {}
276     bool OnInit() { return true; }
277     void OnExit() { delete gs_scheduler; gs_scheduler = NULL; }
278 };
279
280 IMPLEMENT_DYNAMIC_CLASS(wxTimerModule, wxModule)
281
282
283 #endif //wxUSE_TIMER