X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f0599ea91951caa2cda364498ea844be593b8a2a..fab591c5cceff41c0bedaa89af34cd039e2c44e1:/src/common/timercmn.cpp diff --git a/src/common/timercmn.cpp b/src/common/timercmn.cpp index db6eeee6b8..93b58499e5 100644 --- a/src/common/timercmn.cpp +++ b/src/common/timercmn.cpp @@ -1,230 +1,395 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: timercmn.cpp +// Name: common/timercmn.cpp // Purpose: Common timer implementation -// Author: Julian Smart +// Author: +// Original version by Julian Smart +// Vadim Zeitlin got rid of all ifdefs (11.12.99) +// Sylvain Bougnoux added wxStopWatch class +// Guillermo Rodriguez rewrote from scratch (Dic/99) // Modified by: // Created: 04/01/98 // RCS-ID: $Id$ // Copyright: (c) Julian Smart and Markus Holzem -// Licence: wxWindows license +// (c) 1999 Guillermo Rodriguez +// Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxWin headers +// ---------------------------------------------------------------------------- + #ifdef __GNUG__ -//#pragma implementation "timercmn.h" -#pragma implementation + #pragma implementation "timerbase.h" #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif #ifndef WX_PRECOMP -#include "wx/defs.h" -#include "wx/list.h" + #include "wx/intl.h" + #include "wx/log.h" #endif #include "wx/timer.h" +#include "wx/longlong.h" -#if defined(__SVR4__) && !defined(__SYSV__) -#define __SYSV__ -#endif +// ---------------------------------------------------------------------------- +// System headers +// ---------------------------------------------------------------------------- -#include +#if defined(__WIN32__) + #include +#endif -#ifndef __WXMAC__ -#include +#if defined(__WIN32__) && !defined(HAVE_FTIME) && !defined(__MWERKS__) + #define HAVE_FTIME #endif -#if (!defined(__SC__) && !defined(__SGI__) && !defined(__GNUWIN32__) && !defined(__MWERKS__)) || defined(__MINGW32__) -#include +#if defined(__VISAGECPP__) && !defined(HAVE_FTIME) + #define HAVE_FTIME +# if __IBMCPP__ >= 400 + # define ftime(x) _ftime(x) +# endif #endif -#if defined(__linux__) || defined(__SVR4__) || defined(__SYSV__) || defined(__SGI__) || \ - defined(__ALPHA__) || defined(__GNUWIN32__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ - defined(__SALFORDC__) || defined(__EMX__) -#include +#if defined(__MWERKS__) && defined(__WXMSW__) +# undef HAVE_FTIME +# undef HAVE_GETTIMEOFDAY #endif -#ifdef __MINGW32__ -#include "windows.h" +#include +#ifndef __WXMAC__ + #include // for time_t #endif -#if defined(__SUN__) || defined(__OSF__) || defined(__FreeBSD__) -// At least on Sun, ftime is undeclared. -// Need to be verified on other platforms. -extern "C" int ftime(struct timeb *tp); -//extern "C" int gettimeofday(struct timeval *tp, void *); -// extern "C" time_t time(time_t); -// #include -#if defined(__SVR4__) && !defined(__ALPHA__) -// ditto for gettimeofday on Solaris 2.x. -extern "C" int gettimeofday(struct timeval *tp, void *); +#if defined(HAVE_GETTIMEOFDAY) + #include + #include +#elif defined(HAVE_FTIME) + #include #endif + +#ifdef __WXMAC__ + #include + #include #endif +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +#if wxUSE_GUI && wxUSE_TIMER + IMPLEMENT_DYNAMIC_CLASS(wxTimerEvent, wxEvent) +#endif // wxUSE_GUI + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// on some really old systems gettimeofday() doesn't have the second argument, +// define wxGetTimeOfDay() to hide this difference +#ifdef HAVE_GETTIMEOFDAY + #ifdef WX_GETTIMEOFDAY_NO_TZ + struct timezone; + #define wxGetTimeOfDay(tv, tz) gettimeofday(tv) + #else + #define wxGetTimeOfDay(tv, tz) gettimeofday((tv), (tz)) + #endif +#endif // HAVE_GETTIMEOFDAY + +// ============================================================================ +// implementation +// ============================================================================ -/* - * Timer functions - * - */ +// ---------------------------------------------------------------------------- +// wxTimerBase +// ---------------------------------------------------------------------------- -long wxStartTime = 0; -void wxStartTimer(void) +#if wxUSE_GUI && wxUSE_TIMER + +wxTimerBase::~wxTimerBase() { - wxStartTime=wxGetCurrentUTime(); + // this destructor is required for Darwin } -// Returns elapsed time in milliseconds -long wxGetElapsedTime(bool resetTimer) +void wxTimerBase::Notify() { - long oldTime = wxStartTime; - long newTime=wxGetCurrentUTime(); + // the base class version generates an event if it has owner - which it + // should because otherwise nobody can process timer events + wxCHECK_RET( m_owner, _T("wxTimer::Notify() should be overridden.") ); - if (resetTimer) wxStartTime = newTime; - return newTime - oldTime; + wxTimerEvent event(m_idTimer, m_milli); + (void)m_owner->ProcessEvent(event); } - -// Get number of seconds since 00:00:00 GMT, Jan 1st 1970. -long wxGetCurrentTime(void) +bool wxTimerBase::Start(int milliseconds, bool oneShot) { - return wxGetCurrentUTime()/1000; + if ( IsRunning() ) + { + // not stopping the already running timer might work for some + // platforms (no problems under MSW) but leads to mysterious crashes + // on the others (GTK), so to be on the safe side do it here + Stop(); + } + + if ( milliseconds != -1 ) + { + m_milli = milliseconds; + } + + m_oneShot = oneShot; + + return TRUE; } -// return GMT time in millisecond -long wxGetCurrentUTime() +#endif // wxUSE_GUI + +// ---------------------------------------------------------------------------- +// wxStopWatch +// ---------------------------------------------------------------------------- + +#if wxUSE_LONGLONG + +void wxStopWatch::Start(long t) { -#if defined(__xlC__) || defined(__AIX__) || defined(__SVR4__) || defined(__SYSV__) || \ - (defined(__GNUWIN32__) && !defined(__MINGW32__)) // || defined(__AIXV3__) - struct timeval tp; -#if defined(__SYSV__) || (defined (__GNUWIN32__) && !defined (__MINGW32__)) - gettimeofday(&tp, (struct timezone *)NULL); -#else - gettimeofday(&tp); -#endif - return (1000*tp.tv_sec + tp.tv_usec / 1000); -#elif (defined(__SC__) || defined(__SGI__) || defined(___BSDI__) || defined(__ALPHA__) || \ - defined(__MINGW32__)|| defined(__MWERKS__) || defined(__FreeBSD__)) - time_t t0; - struct tm *tp; - time(&t0); - tp = localtime(&t0); - return 1000*(60*(60*tp->tm_hour+tp->tm_min)+tp->tm_sec); -#else - struct timeb tp; - ftime(&tp); - return (1000*tp.time + tp.millitm); -#endif + m_t0 = wxGetLocalTimeMillis() - t; + m_pause = 0; } -//--------------- -// wxChrono class -// This class encapsulates the above fonctions, -// such that several wxChrono can be created -// simultaneously - -wxChrono::wxChrono() +long wxStopWatch::GetElapsedTime() const { - Start(); + return (wxGetLocalTimeMillis() - m_t0).GetLo(); } -void wxChrono::Start(long t) +long wxStopWatch::Time() const { - m_t0=wxGetCurrentUTime()-t; - m_pause=0; + return m_pauseCount ? m_pause : GetElapsedTime(); } -void wxChrono::Pause() +#endif // wxUSE_LONGLONG + +// ---------------------------------------------------------------------------- +// old timer functions superceded by wxStopWatch +// ---------------------------------------------------------------------------- + +#if wxUSE_LONGLONG + +static wxLongLong wxStartTime = 0l; + +// starts the global timer +void wxStartTimer() { - m_pause=wxGetCurrentUTime()-m_t0; + wxStartTime = wxGetLocalTimeMillis(); } -void wxChrono::Resume() +// Returns elapsed time in milliseconds +long wxGetElapsedTime(bool resetTimer) { - m_t0=wxGetCurrentUTime()-m_pause; - m_pause=0; + wxLongLong oldTime = wxStartTime; + wxLongLong newTime = wxGetLocalTimeMillis(); + + if ( resetTimer ) + wxStartTime = newTime; + + return (newTime - oldTime).GetLo(); } -long wxChrono::Time() +#endif // wxUSE_LONGLONG + +// ---------------------------------------------------------------------------- +// the functions to get the current time and timezone info +// ---------------------------------------------------------------------------- + +// Get local time as seconds since 00:00:00, Jan 1st 1970 +long wxGetLocalTime() { - if (m_pause) return m_pause; - return wxGetCurrentUTime()-m_t0; + struct tm tm; + time_t t0, t1; + + // This cannot be made static because mktime can overwrite it. + // + memset(&tm, 0, sizeof(tm)); + tm.tm_year = 70; + tm.tm_mon = 0; + tm.tm_mday = 5; // not Jan 1st 1970 due to mktime 'feature' + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + tm.tm_isdst = -1; // let mktime guess + + // Note that mktime assumes that the struct tm contains local time. + // + t1 = time(&t1); // now + t0 = mktime(&tm); // origin + + // Return the difference in seconds. + // + if (( t0 != (time_t)-1 ) && ( t1 != (time_t)-1 )) + return (long)difftime(t1, t0) + (60 * 60 * 24 * 4); + + wxLogSysError(_("Failed to get the local system time")); + return -1; } +// Get UTC time as seconds since 00:00:00, Jan 1st 1970 +long wxGetUTCTime() +{ + struct tm tm; + struct tm *ptm; + time_t t0, t1; + + // This cannot be made static because mktime can overwrite it + // + memset(&tm, 0, sizeof(tm)); + tm.tm_year = 70; + tm.tm_mon = 0; + tm.tm_mday = 5; // not Jan 1st 1970 due to mktime 'feature' + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + tm.tm_isdst = -1; // let mktime guess + + // Note that mktime assumes that the struct tm contains local time. + // + t1 = time(&t1); // now + t0 = mktime(&tm); // origin in localtime + if (( t0 != (time_t)-1 ) && ( t1 != (time_t)-1 )) + { + // To get t0 as GMT we convert to a struct tm with gmtime, + // and then back again. + // + ptm = gmtime(&t0); -// EXPERIMENTAL: comment this out if it doesn't compile. -#ifndef __VMS__ -bool wxGetLocalTime(long *timeZone, int *dstObserved) + if (ptm) + { + memcpy(&tm, ptm, sizeof(tm)); + t0 = mktime(&tm); + + if (t0 != (time_t)-1 ) + return (long)difftime(t1, t0) + (60 * 60 * 24 * 4); + wxLogSysError(_("mktime() failed")); + } + else + { + wxLogSysError(_("gmtime() failed")); + } + } + + wxLogError(_("Failed to get the UTC system time.")); + + return -1; +} + +#if wxUSE_LONGLONG + +// Get local time as milliseconds since 00:00:00, Jan 1st 1970 +wxLongLong wxGetLocalTimeMillis() { -#if defined(__MINGW32__) - time_t t0; - struct tm *tp; - time(&t0); - tp = localtime(&t0); -# if __GNUC__ == 2 && __GNUC_MINOR__ <= 8 - // gcc 2.8.x or earlier - timeb tz; - ftime(& tz); - *timeZone = tz._timezone; -# else - // egcs or gcc 2.95 - *timeZone = _timezone; // tp->tm_gmtoff; // ??? -# endif - *dstObserved = tp->tm_isdst; -#else -// not mingw32... -#if (((defined(__SYSV__) && !defined(__HPUX__)) || defined(__MSDOS__) || defined(__WXMSW__) || defined(__WXPM__)) \ - && !defined(__GNUWIN32__) && !defined(__MWERKS__) ) -# if defined(__BORLANDC__) - /* Borland uses underscores */ - *timeZone = _timezone; - *dstObserved = _daylight; -# elif defined(__SALFORDC__) - *timeZone = _timezone; - *dstObserved = daylight; -# elif defined(__VISAGECPP__) - *timeZone = _timezone; - *dstObserved = daylight; -# else - *timeZone = timezone; - *dstObserved = daylight; -# endif -#elif defined(__xlC__) || defined(__AIX__) || defined(__SVR4__) || defined(__SYSV__) || defined(__MWERKS__) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) // || defined(__AIXV3__) -# ifndef __MWERKS__ // shouldn't this be one scope below ? - struct timeval tp; -# endif -# if defined(__SYSV__) || (defined(__GNUWIN32__) && !defined(__MINGW32)) - struct timezone tz; - gettimeofday(&tp, &tz); - *timeZone = 60*(tz.tz_minuteswest); - *dstObserved = tz.tz_dsttime; -# else - time_t t0; - struct tm *tp; - time(&t0); - tp = localtime(&t0); -# ifndef __MWERKS__ - *timeZone = tp->tm_gmtoff; // ??? -# else - *timeZone = 0 ; -# endif - *dstObserved = tp->tm_isdst; -#endif -#elif defined(__WXSTUBS__) - return FALSE; -#else -// #error wxGetLocalTime not implemented. - struct timeval tp; - struct timezone tz; - gettimeofday(&tp, &tz); - *timeZone = 60*(tz.tz_minuteswest); - *dstObserved = tz.tz_dsttime; -#endif + wxLongLong val = 1000l; + + // If possible, use a function which avoids conversions from + // broken-up time structures to milliseconds + +#if defined(__WXMSW__) && defined(__MWERKS__) + // This should probably be the way all WXMSW compilers should do it + // Go direct to the OS for time + + SYSTEMTIME thenst = { 1970, 1, 4, 1, 0, 0, 0, 0 }; // 00:00:00 Jan 1st 1970 + FILETIME thenft; + SystemTimeToFileTime( &thenst, &thenft ); + wxLongLong then( thenft.dwHighDateTime, thenft.dwLowDateTime ); // time in 100 nanoseconds + + SYSTEMTIME nowst; + GetLocalTime( &nowst ); + FILETIME nowft; + SystemTimeToFileTime( &nowst, &nowft ); + wxLongLong now( nowft.dwHighDateTime, nowft.dwLowDateTime ); // time in 100 nanoseconds + + return ( now - then ) / 10000.0; // time from 00:00:00 Jan 1st 1970 to now in milliseconds + +#elif defined(HAVE_GETTIMEOFDAY) + struct timeval tp; + if ( wxGetTimeOfDay(&tp, (struct timezone *)NULL) != -1 ) + { + val *= tp.tv_sec; + return (val + (tp.tv_usec / 1000)); + } + else + { + wxLogError(_("wxGetTimeOfDay failed.")); + return 0; + } +#elif defined(HAVE_FTIME) + struct timeb tp; + + // ftime() is void and not int in some mingw32 headers, so don't + // test the return code (well, it shouldn't fail anyhow...) + (void)ftime(&tp); + val *= tp.time; + return (val + tp.millitm); +#elif defined(__WXMAC__) + + unsigned long secs ; + UInt64 gMilliAtStart = 0 ; + Nanoseconds upTime = AbsoluteToNanoseconds( UpTime() ) ; + if ( gMilliAtStart == 0 ) + { + time_t start = time(NULL) ; + gMilliAtStart = ((UInt64) start) * 1000L ; + gMilliAtStart -= upTime.lo / 1000 ; + gMilliAtStart -= ( ( (UInt64) upTime.hi ) << 32 ) / 1000 ; + } + UInt64 millival = gMilliAtStart ; + millival += upTime.lo / 1000 ; + millival += ( ( (UInt64) upTime.hi ) << 32 ) / 1000 ; + return millival ; +#else // no gettimeofday() nor ftime() + // We use wxGetLocalTime() to get the seconds since + // 00:00:00 Jan 1st 1970 and then whatever is available + // to get millisecond resolution. + // + // NOTE that this might lead to a problem if the clocks + // use different sources, so this approach should be + // avoided where possible. + + val *= wxGetLocalTime(); + +// GRG: This will go soon as all WIN32 seem to have ftime +#if defined (__WIN32__) + // If your platform/compiler needs to use two different functions + // to get ms resolution, please do NOT just shut off these warnings, + // drop me a line instead at + #warning "Possible clock skew bug in wxGetLocalTimeMillis()!" + + SYSTEMTIME st; + ::GetLocalTime(&st); + val += st.wMilliseconds; +#else // !Win32 + // If your platform/compiler does not support ms resolution please + // do NOT just shut off these warnings, drop me a line instead at + // + + #if defined(__VISUALC__) || defined (__WATCOMC__) + #pragma message("wxStopWatch will be up to second resolution!") + #elif defined(__BORLANDC__) + #pragma message "wxStopWatch will be up to second resolution!" + #else + #warning "wxStopWatch will be up to second resolution!" + #endif // compiler #endif - // __MINGW32__ - return TRUE; + + return val; + +#endif // time functions } -#endif + +#endif // wxUSE_LONGLONG +