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