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