X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/07cf98cb8eb7625eeffc95e407a9fa1ad863b451..20ea6894a2660c453c3255a66aa9f7e24cf97ec8:/src/common/timercmn.cpp diff --git a/src/common/timercmn.cpp b/src/common/timercmn.cpp index 63a4eced88..93b58499e5 100644 --- a/src/common/timercmn.cpp +++ b/src/common/timercmn.cpp @@ -1,12 +1,17 @@ ///////////////////////////////////////////////////////////////////////////// // Name: common/timercmn.cpp // Purpose: Common timer implementation -// Author: Julian Smart -// Modified by: Vadim Zeitlin on 12.11.99 to get rid of all ifdefs +// 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 ///////////////////////////////////////////////////////////////////////////// // ============================================================================ @@ -14,7 +19,7 @@ // ============================================================================ // ---------------------------------------------------------------------------- -// headers +// wxWin headers // ---------------------------------------------------------------------------- #ifdef __GNUG__ @@ -34,35 +39,56 @@ #endif #include "wx/timer.h" +#include "wx/longlong.h" -// I'm told VMS is POSIX, so should have localtime() -#if defined(__WXMSW__) || defined(__VMS__) - // configure might have found it already for us - #ifndef HAVE_LOCALTIME - #define HAVE_LOCALTIME - #endif +// ---------------------------------------------------------------------------- +// System headers +// ---------------------------------------------------------------------------- + +#if defined(__WIN32__) + #include #endif -// TODO: #define WX_GMTOFF_IN_TM for Windows compilers which have it here +#if defined(__WIN32__) && !defined(HAVE_FTIME) && !defined(__MWERKS__) + #define HAVE_FTIME +#endif -#if defined(__WIN32__) && !defined(WX_GMTOFF_IN_TM) - #include +#if defined(__VISAGECPP__) && !defined(HAVE_FTIME) + #define HAVE_FTIME +# if __IBMCPP__ >= 400 + # define ftime(x) _ftime(x) +# endif +#endif + +#if defined(__MWERKS__) && defined(__WXMSW__) +# undef HAVE_FTIME +# undef HAVE_GETTIMEOFDAY +#endif + +#include +#ifndef __WXMAC__ + #include // for time_t #endif #if defined(HAVE_GETTIMEOFDAY) #include #include -#elif defined(HAVE_LOCALTIME) - #include - #ifndef __WXMAC__ - #include // for time_t - #endif #elif defined(HAVE_FTIME) #include -#else - #error "no function to find the current time on this system" #endif +#ifdef __WXMAC__ + #include + #include +#endif +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +#if wxUSE_GUI && wxUSE_TIMER + IMPLEMENT_DYNAMIC_CLASS(wxTimerEvent, wxEvent) +#endif // wxUSE_GUI + // ---------------------------------------------------------------------------- // macros // ---------------------------------------------------------------------------- @@ -82,159 +108,288 @@ // implementation // ============================================================================ +// ---------------------------------------------------------------------------- +// wxTimerBase +// ---------------------------------------------------------------------------- + +#if wxUSE_GUI && wxUSE_TIMER + +wxTimerBase::~wxTimerBase() +{ + // this destructor is required for Darwin +} + +void wxTimerBase::Notify() +{ + // 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.") ); + + wxTimerEvent event(m_idTimer, m_milli); + (void)m_owner->ProcessEvent(event); +} + +bool wxTimerBase::Start(int milliseconds, bool oneShot) +{ + 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; +} + +#endif // wxUSE_GUI + // ---------------------------------------------------------------------------- // wxStopWatch // ---------------------------------------------------------------------------- +#if wxUSE_LONGLONG + void wxStopWatch::Start(long t) { - m_t0 = wxGetCurrentMTime() - t; - + m_t0 = wxGetLocalTimeMillis() - t; m_pause = 0; } +long wxStopWatch::GetElapsedTime() const +{ + return (wxGetLocalTimeMillis() - m_t0).GetLo(); +} + long wxStopWatch::Time() const { - return m_pause ? m_pause : GetElapsedTime(); + return m_pauseCount ? m_pause : GetElapsedTime(); } +#endif // wxUSE_LONGLONG + // ---------------------------------------------------------------------------- // old timer functions superceded by wxStopWatch // ---------------------------------------------------------------------------- -static long wxStartTime = 0; +#if wxUSE_LONGLONG + +static wxLongLong wxStartTime = 0l; // starts the global timer void wxStartTimer() { - wxStartTime = wxGetCurrentMTime(); + wxStartTime = wxGetLocalTimeMillis(); } // Returns elapsed time in milliseconds long wxGetElapsedTime(bool resetTimer) { - long oldTime = wxStartTime; - long newTime = wxGetCurrentMTime(); + wxLongLong oldTime = wxStartTime; + wxLongLong newTime = wxGetLocalTimeMillis(); if ( resetTimer ) wxStartTime = newTime; - return newTime - oldTime; + return (newTime - oldTime).GetLo(); } - -// Get number of seconds since 00:00:00 GMT, Jan 1st 1970. -long wxGetCurrentTime() -{ - return wxGetCurrentMTime() / 1000; -} +#endif // wxUSE_LONGLONG // ---------------------------------------------------------------------------- // the functions to get the current time and timezone info // ---------------------------------------------------------------------------- -// return GMT time in millisecond -long wxGetCurrentMTime() +// Get local time as seconds since 00:00:00, Jan 1st 1970 +long wxGetLocalTime() { -#if defined(HAVE_LOCALTIME) - time_t t0 = time(&t0); - if ( t0 != (time_t)-1 ) + 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 )) { - struct tm *tp = localtime(&t0); + // To get t0 as GMT we convert to a struct tm with gmtime, + // and then back again. + // + ptm = gmtime(&t0); - if ( tp ) + if (ptm) { - return 1000*(60*(60*tp->tm_hour+tp->tm_min)+tp->tm_sec); + 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")); } } -#elif defined(HAVE_GETTIMEOFDAY) - struct timeval tp; - if ( wxGetTimeOfDay(&tp, (struct timezone *)NULL) != -1 ) - { - return (1000*tp.tv_sec + tp.tv_usec / 1000); - } -#elif defined(HAVE_FTIME) - struct timeb tp; - if ( ftime(&tp) == 0 ) - { - return (1000*tp.time + tp.millitm); - } -#else - #error "no function to find the current time on this system" -#endif - wxLogSysError(_("Failed to get the system time")); + wxLogError(_("Failed to get the UTC system time.")); return -1; } -bool wxGetLocalTime(long *timeZone, int *dstObserved) +#if wxUSE_LONGLONG + +// Get local time as milliseconds since 00:00:00, Jan 1st 1970 +wxLongLong wxGetLocalTimeMillis() { -#if defined(HAVE_LOCALTIME) && defined(WX_GMTOFF_IN_TM) - time_t t0 = time(&t0); - if ( t0 != (time_t)-1 ) - { - struct tm *tm = localtime(&t0); + wxLongLong val = 1000l; - if ( tm ) - { - *timeZone = tm->tm_gmtoff; - *dstObserved = tm->tm_isdst; + // If possible, use a function which avoids conversions from + // broken-up time structures to milliseconds - return TRUE; - } - } -#elif defined(HAVE_GETTIMEOFDAY) && !defined(WX_GETTIMEOFDAY_NO_TZ) +#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; - struct timezone tz; - if ( gettimeofday(&tp, &tz) != -1 ) + if ( wxGetTimeOfDay(&tp, (struct timezone *)NULL) != -1 ) { - *timeZone = 60*tz.tz_minuteswest; - *dstObserved = tz.tz_dsttime; - - return TRUE; + val *= tp.tv_sec; + return (val + (tp.tv_usec / 1000)); } -#elif defined(HAVE_FTIME) - struct timeb tb; - if ( ftime(&tb) == 0 ) + else { - *timeZone = 60*tb.timezone; - *dstObserved = tb.dstflag; + wxLogError(_("wxGetTimeOfDay failed.")); + return 0; } -#else // no standard function return tz info - // special hacks for known compilers - #if defined(__BORLANDC__) || defined(__VISUALC__) - *timeZone = _timezone; - *dstObserved = _daylight; - #elif defined(__SALFORDC__) - *timeZone = _timezone; - *dstObserved = daylight; - #elif defined(__VISAGECPP__) - *timeZone = _timezone; - *dstObserved = daylight; - #elif defined(__WIN32__) - TIME_ZONE_INFORMATION tzInfo; - switch ( GetTimeZoneInformation(&tzInfo) ) - { - default: - wxFAIL_MSG(_T("unknown GetTimeZoneInformation return code")); - // fall through - - case TIME_ZONE_ID_UNKNOWN: - case TIME_ZONE_ID_STANDARD: - *dstObserved = FALSE; - break; - - case TIME_ZONE_ID_DAYLIGHT: - *dstObserved = TRUE; - break; - } +#elif defined(HAVE_FTIME) + struct timeb tp; - *timeZone = 60*tzInfo.Bias; + // 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 - wxFAIL_MSG(_T("wxGetLocalTime() not implemented")); + #warning "wxStopWatch will be up to second resolution!" #endif // compiler -#endif // all ways in the known Universe to get tz info +#endif + + return val; - return FALSE; +#endif // time functions } + +#endif // wxUSE_LONGLONG +