]> git.saurik.com Git - wxWidgets.git/blob - src/unix/timerunx.cpp
Update OpenVMS compile support
[wxWidgets.git] / src / unix / timerunx.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/unix/timerunx.cpp
3 // Purpose: wxTimer implementation for non-GUI applications under Unix
4 // Author: Lukasz Michalski
5 // Created: 15/01/2005
6 // RCS-ID: $Id$
7 // Copyright: (c) 2007 Lukasz Michalski
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 #include "wx/wxprec.h"
20
21 #if wxUSE_TIMER
22
23 #ifndef WX_PRECOMP
24 #include "wx/log.h"
25 #include "wx/module.h"
26 #include "wx/app.h"
27 #include "wx/list.h"
28 #include "wx/hashmap.h"
29 #include "wx/event.h"
30 #endif
31
32 #include "wx/apptrait.h"
33 #include "wx/longlong.h"
34
35 #include <sys/time.h>
36 #include <signal.h>
37
38 #include "wx/unix/private/timer.h"
39
40 #include "wx/listimpl.cpp"
41 WX_DEFINE_LIST(wxTimerList)
42
43 // trace mask for the debugging messages used here
44 #define wxTrace_Timer wxT("timer")
45
46 // ----------------------------------------------------------------------------
47 // local functions
48 // ----------------------------------------------------------------------------
49
50 // helper function to format wxUsecClock_t
51 static inline wxString wxUsecClockAsString(wxUsecClock_t usec)
52 {
53 #if wxUSE_LONGLONG
54 return usec.ToString();
55 #else // wxUsecClock_t == double
56 return wxString::Format(_T("%.0f"), usec);
57 #endif
58 }
59
60 // ============================================================================
61 // wxTimerScheduler implementation
62 // ============================================================================
63
64 wxTimerScheduler *wxTimerScheduler::ms_instance = NULL;
65
66 wxTimerScheduler::~wxTimerScheduler()
67 {
68 for ( wxTimerList::iterator node = m_timers.begin();
69 node != m_timers.end();
70 ++node )
71 {
72 delete *node;
73 }
74 }
75
76 void wxTimerScheduler::AddTimer(wxUnixTimerImpl *timer, wxUsecClock_t expiration)
77 {
78 DoAddTimer(new wxTimerSchedule(timer, expiration));
79 }
80
81 void wxTimerScheduler::DoAddTimer(wxTimerSchedule *s)
82 {
83 // do an insertion sort to keep the list sorted in expiration order
84 wxTimerList::iterator node;
85 for ( node = m_timers.begin(); node != m_timers.end(); ++node )
86 {
87 wxASSERT_MSG( (*node)->m_timer != s->m_timer,
88 _T("adding the same timer twice?") );
89
90 if ( (*node)->m_expiration > s->m_expiration )
91 break;
92 }
93
94 m_timers.insert(node, s);
95
96 wxLogTrace(wxTrace_Timer, wxT("Inserted timer %d expiring at %s"),
97 s->m_timer->GetId(),
98 wxUsecClockAsString(s->m_expiration).c_str());
99 }
100
101 void wxTimerScheduler::RemoveTimer(wxUnixTimerImpl *timer)
102 {
103 wxLogTrace(wxTrace_Timer, wxT("Removing timer %d"), timer->GetId());
104
105 for ( wxTimerList::iterator node = m_timers.begin();
106 node != m_timers.end();
107 ++node )
108 {
109 if ( (*node)->m_timer == timer )
110 {
111 delete *node;
112 m_timers.erase(node);
113 return;
114 }
115 }
116
117 wxFAIL_MSG( _T("removing inexistent timer?") );
118 }
119
120 bool wxTimerScheduler::GetNext(wxUsecClock_t *remaining) const
121 {
122 if ( m_timers.empty() )
123 return false;
124
125 wxCHECK_MSG( remaining, false, _T("NULL pointer") );
126
127 *remaining = (*m_timers.begin())->m_expiration - wxGetLocalTimeUsec();
128 if ( *remaining < 0 )
129 {
130 // timer already expired, don't wait at all before notifying it
131 *remaining = 0;
132 }
133
134 return true;
135 }
136
137 void wxTimerScheduler::NotifyExpired()
138 {
139 if ( m_timers.empty() )
140 return;
141
142 const wxUsecClock_t now = wxGetLocalTimeUsec();
143
144 wxTimerList::iterator cur,
145 next;
146 for ( cur = m_timers.begin(); cur != m_timers.end(); cur = next )
147 {
148 wxTimerSchedule * const s = *cur;
149 if ( s->m_expiration > now )
150 {
151 // as the list is sorted by expiration time, we can skip the rest
152 break;
153 }
154
155 // remember next as we will delete the node pointed to by cur
156 next = cur;
157 ++next;
158
159 m_timers.erase(cur);
160
161 // check whether we need to keep this timer
162 wxUnixTimerImpl * const timer = s->m_timer;
163 if ( timer->IsOneShot() )
164 {
165 // the timer needs to be stopped but don't call its Stop() from
166 // here as it would attempt to remove the timer from our list and
167 // we had already done it, so we just need to reset its state
168 timer->MarkStopped();
169
170 // don't need it any more
171 delete s;
172 }
173 else // reschedule the next timer expiration
174 {
175 // always keep the expiration time in the future, i.e. base it on
176 // the current time instead of just offsetting it from the current
177 // expiration time because it could happen that we're late and the
178 // current expiration time is (far) in the past
179 s->m_expiration = now + timer->GetInterval()*1000;
180 DoAddTimer(s);
181 }
182
183 // and finally notify the timer
184 timer->Notify();
185 }
186 }
187
188 // ============================================================================
189 // wxUnixTimerImpl implementation
190 // ============================================================================
191
192 wxUnixTimerImpl::wxUnixTimerImpl(wxTimer* timer)
193 : wxTimerImpl(timer)
194 {
195 m_isRunning = false;
196 }
197
198 bool wxUnixTimerImpl::Start(int milliseconds, bool oneShot)
199 {
200 // notice that this will stop an already running timer
201 wxTimerImpl::Start(milliseconds, oneShot);
202
203 wxTimerScheduler::Get().AddTimer(this, wxGetLocalTimeUsec() + m_milli*1000);
204 m_isRunning = true;
205
206 return true;
207 }
208
209 void wxUnixTimerImpl::Stop()
210 {
211 if ( m_isRunning )
212 {
213 wxTimerScheduler::Get().RemoveTimer(this);
214
215 m_isRunning = false;
216 }
217 }
218
219 bool wxUnixTimerImpl::IsRunning() const
220 {
221 return m_isRunning;
222 }
223
224 wxUnixTimerImpl::~wxUnixTimerImpl()
225 {
226 wxASSERT_MSG( !m_isRunning, _T("must have been stopped before") );
227 }
228
229 // ============================================================================
230 // wxTimerUnixModule: responsible for freeing the global timer scheduler
231 // ============================================================================
232
233 class wxTimerUnixModule : public wxModule
234 {
235 public:
236 wxTimerUnixModule() {}
237 virtual bool OnInit() { return true; }
238 virtual void OnExit() { wxTimerScheduler::Shutdown(); }
239
240 DECLARE_DYNAMIC_CLASS(wxTimerUnixModule)
241 };
242
243 IMPLEMENT_DYNAMIC_CLASS(wxTimerUnixModule, wxModule)
244
245 // ============================================================================
246 // global functions
247 // ============================================================================
248
249 wxUsecClock_t wxGetLocalTimeUsec()
250 {
251 #ifdef HAVE_GETTIMEOFDAY
252 struct timeval tv;
253 if ( wxGetTimeOfDay(&tv) != -1 )
254 {
255 wxUsecClock_t val = 1000000L; // usec/sec
256 val *= tv.tv_sec;
257 return val + tv.tv_usec;
258 }
259 #endif // HAVE_GETTIMEOFDAY
260
261 return wxGetLocalTimeMillis() * 1000L;
262 }
263
264 wxTimerImpl *wxConsoleAppTraits::CreateTimerImpl(wxTimer *timer)
265 {
266 return new wxUnixTimerImpl(timer);
267 }
268
269 #endif // wxUSE_TIMER
270