]> git.saurik.com Git - wxWidgets.git/blob - src/common/timercmn.cpp
Split this out from other changes to keep things sane..
[wxWidgets.git] / src / common / timercmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/timercmn.cpp
3 // Purpose: Common timer implementation
4 // Author:
5 // Original version by Julian Smart
6 // Vadim Zeitlin got rid of all ifdefs (11.12.99)
7 // Sylvain Bougnoux added wxStopWatch class
8 // Guillermo Rodriguez <guille@iies.es> rewrote from scratch (Dic/99)
9 // Modified by:
10 // Created: 04/01/98
11 // RCS-ID: $Id$
12 // Copyright: (c) Julian Smart and Markus Holzem
13 // (c) 1999 Guillermo Rodriguez <guille@iies.es>
14 // Licence: wxWindows license
15 /////////////////////////////////////////////////////////////////////////////
16
17 // ============================================================================
18 // declarations
19 // ============================================================================
20
21 // ----------------------------------------------------------------------------
22 // wxWin headers
23 // ----------------------------------------------------------------------------
24
25 #ifdef __GNUG__
26 #pragma implementation "timerbase.h"
27 #endif
28
29 // For compilers that support precompilation, includes "wx.h".
30 #include "wx/wxprec.h"
31
32 #ifdef __BORLANDC__
33 #pragma hdrstop
34 #endif
35
36 #ifndef WX_PRECOMP
37 #include "wx/intl.h"
38 #include "wx/log.h"
39 #include "wx/thread.h"
40 #endif
41
42 #include "wx/timer.h"
43 #include "wx/longlong.h"
44
45 // ----------------------------------------------------------------------------
46 // System headers
47 // ----------------------------------------------------------------------------
48
49 #if defined(__WIN32__)
50 #include <windows.h>
51 #endif
52
53 #if defined(__WIN32__) && !defined(HAVE_FTIME) && !defined(__MWERKS__)
54 #define HAVE_FTIME
55 #endif
56
57 #if defined(__VISAGECPP__) && !defined(HAVE_FTIME)
58 #define HAVE_FTIME
59 # if __IBMCPP__ >= 400
60 # define ftime(x) _ftime(x)
61 # endif
62 #endif
63
64 #if defined(__MWERKS__) && defined(__WXMSW__)
65 # undef HAVE_FTIME
66 # undef HAVE_GETTIMEOFDAY
67 #endif
68
69 #include <time.h>
70 #ifndef __WXMAC__
71 #include <sys/types.h> // for time_t
72 #endif
73
74 #if defined(HAVE_GETTIMEOFDAY)
75 #include <sys/time.h>
76 #include <unistd.h>
77 #elif defined(HAVE_FTIME)
78 #include <sys/timeb.h>
79 #endif
80
81 #ifdef __WXMAC__
82 #include <Timer.h>
83 #include <DriverServices.h>
84 #endif
85 // ----------------------------------------------------------------------------
86 // wxWin macros
87 // ----------------------------------------------------------------------------
88
89 #if wxUSE_GUI && wxUSE_TIMER
90 IMPLEMENT_DYNAMIC_CLASS(wxTimerEvent, wxEvent)
91 #endif // wxUSE_GUI
92
93 // ----------------------------------------------------------------------------
94 // macros
95 // ----------------------------------------------------------------------------
96
97 // on some really old systems gettimeofday() doesn't have the second argument,
98 // define wxGetTimeOfDay() to hide this difference
99 #ifdef HAVE_GETTIMEOFDAY
100 #ifdef WX_GETTIMEOFDAY_NO_TZ
101 struct timezone;
102 #define wxGetTimeOfDay(tv, tz) gettimeofday(tv)
103 #else
104 #define wxGetTimeOfDay(tv, tz) gettimeofday((tv), (tz))
105 #endif
106 #endif // HAVE_GETTIMEOFDAY
107
108 // ============================================================================
109 // implementation
110 // ============================================================================
111
112 // ----------------------------------------------------------------------------
113 // wxTimerBase
114 // ----------------------------------------------------------------------------
115
116 #if wxUSE_GUI && wxUSE_TIMER
117
118 wxTimerBase::~wxTimerBase()
119 {
120 // this destructor is required for Darwin
121 }
122
123 void wxTimerBase::Notify()
124 {
125 // the base class version generates an event if it has owner - which it
126 // should because otherwise nobody can process timer events
127 wxCHECK_RET( m_owner, _T("wxTimer::Notify() should be overridden.") );
128
129 wxTimerEvent event(m_idTimer, m_milli);
130 (void)m_owner->ProcessEvent(event);
131 }
132
133 bool wxTimerBase::Start(int milliseconds, bool oneShot)
134 {
135 // under MSW timers only work when they're started from the main thread so
136 // let the caller know about it
137 #if wxUSE_THREADS
138 wxASSERT_MSG( wxThread::IsMain(),
139 _T("timer can only be started from the main thread") );
140 #endif // wxUSE_THREADS
141
142 if ( IsRunning() )
143 {
144 // not stopping the already running timer might work for some
145 // platforms (no problems under MSW) but leads to mysterious crashes
146 // on the others (GTK), so to be on the safe side do it here
147 Stop();
148 }
149
150 if ( milliseconds != -1 )
151 {
152 m_milli = milliseconds;
153 }
154
155 m_oneShot = oneShot;
156
157 return TRUE;
158 }
159
160 #endif // wxUSE_GUI
161
162 // ----------------------------------------------------------------------------
163 // wxStopWatch
164 // ----------------------------------------------------------------------------
165
166 #if wxUSE_LONGLONG
167
168 void wxStopWatch::Start(long t)
169 {
170 m_t0 = wxGetLocalTimeMillis() - t;
171 m_pause = 0;
172 }
173
174 long wxStopWatch::GetElapsedTime() const
175 {
176 return (wxGetLocalTimeMillis() - m_t0).GetLo();
177 }
178
179 long wxStopWatch::Time() const
180 {
181 return m_pauseCount ? m_pause : GetElapsedTime();
182 }
183
184 #endif // wxUSE_LONGLONG
185
186 // ----------------------------------------------------------------------------
187 // old timer functions superceded by wxStopWatch
188 // ----------------------------------------------------------------------------
189
190 #if wxUSE_LONGLONG
191
192 static wxLongLong wxStartTime = 0l;
193
194 // starts the global timer
195 void wxStartTimer()
196 {
197 wxStartTime = wxGetLocalTimeMillis();
198 }
199
200 // Returns elapsed time in milliseconds
201 long wxGetElapsedTime(bool resetTimer)
202 {
203 wxLongLong oldTime = wxStartTime;
204 wxLongLong newTime = wxGetLocalTimeMillis();
205
206 if ( resetTimer )
207 wxStartTime = newTime;
208
209 return (newTime - oldTime).GetLo();
210 }
211
212 #endif // wxUSE_LONGLONG
213
214 // ----------------------------------------------------------------------------
215 // the functions to get the current time and timezone info
216 // ----------------------------------------------------------------------------
217
218 // Get local time as seconds since 00:00:00, Jan 1st 1970
219 long wxGetLocalTime()
220 {
221 struct tm tm;
222 time_t t0, t1;
223
224 // This cannot be made static because mktime can overwrite it.
225 //
226 memset(&tm, 0, sizeof(tm));
227 tm.tm_year = 70;
228 tm.tm_mon = 0;
229 tm.tm_mday = 5; // not Jan 1st 1970 due to mktime 'feature'
230 tm.tm_hour = 0;
231 tm.tm_min = 0;
232 tm.tm_sec = 0;
233 tm.tm_isdst = -1; // let mktime guess
234
235 // Note that mktime assumes that the struct tm contains local time.
236 //
237 t1 = time(&t1); // now
238 t0 = mktime(&tm); // origin
239
240 // Return the difference in seconds.
241 //
242 if (( t0 != (time_t)-1 ) && ( t1 != (time_t)-1 ))
243 return (long)difftime(t1, t0) + (60 * 60 * 24 * 4);
244
245 wxLogSysError(_("Failed to get the local system time"));
246 return -1;
247 }
248
249 // Get UTC time as seconds since 00:00:00, Jan 1st 1970
250 long wxGetUTCTime()
251 {
252 struct tm tm;
253 struct tm *ptm;
254 time_t t0, t1;
255
256 // This cannot be made static because mktime can overwrite it
257 //
258 memset(&tm, 0, sizeof(tm));
259 tm.tm_year = 70;
260 tm.tm_mon = 0;
261 tm.tm_mday = 5; // not Jan 1st 1970 due to mktime 'feature'
262 tm.tm_hour = 0;
263 tm.tm_min = 0;
264 tm.tm_sec = 0;
265 tm.tm_isdst = -1; // let mktime guess
266
267 // Note that mktime assumes that the struct tm contains local time.
268 //
269 t1 = time(&t1); // now
270 t0 = mktime(&tm); // origin in localtime
271
272 if (( t0 != (time_t)-1 ) && ( t1 != (time_t)-1 ))
273 {
274 // To get t0 as GMT we convert to a struct tm with gmtime,
275 // and then back again.
276 //
277 ptm = gmtime(&t0);
278
279 if (ptm)
280 {
281 memcpy(&tm, ptm, sizeof(tm));
282 t0 = mktime(&tm);
283
284 if (t0 != (time_t)-1 )
285 return (long)difftime(t1, t0) + (60 * 60 * 24 * 4);
286 wxLogSysError(_("mktime() failed"));
287 }
288 else
289 {
290 wxLogSysError(_("gmtime() failed"));
291 }
292 }
293
294 wxLogError(_("Failed to get the UTC system time."));
295
296 return -1;
297 }
298
299 #if wxUSE_LONGLONG
300
301 // Get local time as milliseconds since 00:00:00, Jan 1st 1970
302 wxLongLong wxGetLocalTimeMillis()
303 {
304 wxLongLong val = 1000l;
305
306 // If possible, use a function which avoids conversions from
307 // broken-up time structures to milliseconds
308
309 #if defined(__WXMSW__) && defined(__MWERKS__)
310 // This should probably be the way all WXMSW compilers should do it
311 // Go direct to the OS for time
312
313 SYSTEMTIME thenst = { 1970, 1, 4, 1, 0, 0, 0, 0 }; // 00:00:00 Jan 1st 1970
314 FILETIME thenft;
315 SystemTimeToFileTime( &thenst, &thenft );
316 wxLongLong then( thenft.dwHighDateTime, thenft.dwLowDateTime ); // time in 100 nanoseconds
317
318 SYSTEMTIME nowst;
319 GetLocalTime( &nowst );
320 FILETIME nowft;
321 SystemTimeToFileTime( &nowst, &nowft );
322 wxLongLong now( nowft.dwHighDateTime, nowft.dwLowDateTime ); // time in 100 nanoseconds
323
324 return ( now - then ) / 10000.0; // time from 00:00:00 Jan 1st 1970 to now in milliseconds
325
326 #elif defined(HAVE_GETTIMEOFDAY)
327 struct timeval tp;
328 if ( wxGetTimeOfDay(&tp, (struct timezone *)NULL) != -1 )
329 {
330 val *= tp.tv_sec;
331 return (val + (tp.tv_usec / 1000));
332 }
333 else
334 {
335 wxLogError(_("wxGetTimeOfDay failed."));
336 return 0;
337 }
338 #elif defined(HAVE_FTIME)
339 struct timeb tp;
340
341 // ftime() is void and not int in some mingw32 headers, so don't
342 // test the return code (well, it shouldn't fail anyhow...)
343 (void)ftime(&tp);
344 val *= tp.time;
345 return (val + tp.millitm);
346 #elif defined(__WXMAC__)
347
348 UInt64 gMilliAtStart = 0 ;
349 Nanoseconds upTime = AbsoluteToNanoseconds( UpTime() ) ;
350 if ( gMilliAtStart == 0 )
351 {
352 time_t start = time(NULL) ;
353 gMilliAtStart = ((UInt64) start) * 1000L ;
354 gMilliAtStart -= upTime.lo / 1000 ;
355 gMilliAtStart -= ( ( (UInt64) upTime.hi ) << 32 ) / 1000 ;
356 }
357 UInt64 millival = gMilliAtStart ;
358 millival += upTime.lo / 1000 ;
359 millival += ( ( (UInt64) upTime.hi ) << 32 ) / 1000 ;
360 val = millival ;
361 return val ;
362 #else // no gettimeofday() nor ftime()
363 // We use wxGetLocalTime() to get the seconds since
364 // 00:00:00 Jan 1st 1970 and then whatever is available
365 // to get millisecond resolution.
366 //
367 // NOTE that this might lead to a problem if the clocks
368 // use different sources, so this approach should be
369 // avoided where possible.
370
371 val *= wxGetLocalTime();
372
373 // GRG: This will go soon as all WIN32 seem to have ftime
374 #if defined (__WIN32__)
375 // If your platform/compiler needs to use two different functions
376 // to get ms resolution, please do NOT just shut off these warnings,
377 // drop me a line instead at <guille@iies.es>
378 #warning "Possible clock skew bug in wxGetLocalTimeMillis()!"
379
380 SYSTEMTIME st;
381 ::GetLocalTime(&st);
382 val += st.wMilliseconds;
383 #else // !Win32
384 // If your platform/compiler does not support ms resolution please
385 // do NOT just shut off these warnings, drop me a line instead at
386 // <guille@iies.es>
387
388 #if defined(__VISUALC__) || defined (__WATCOMC__)
389 #pragma message("wxStopWatch will be up to second resolution!")
390 #elif defined(__BORLANDC__)
391 #pragma message "wxStopWatch will be up to second resolution!"
392 #else
393 #warning "wxStopWatch will be up to second resolution!"
394 #endif // compiler
395 #endif
396
397 return val;
398
399 #endif // time functions
400 }
401
402 #endif // wxUSE_LONGLONG
403