The rounded corners look really dumb at this size.
[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 // Copyright: (c) 2007 Lukasz Michalski
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 #include "wx/wxprec.h"
19
20 #if wxUSE_TIMER
21
22 #ifndef WX_PRECOMP
23 #include "wx/log.h"
24 #include "wx/module.h"
25 #include "wx/app.h"
26 #include "wx/list.h"
27 #include "wx/hashmap.h"
28 #include "wx/event.h"
29 #endif
30
31 #include "wx/apptrait.h"
32 #include "wx/longlong.h"
33 #include "wx/time.h"
34 #include "wx/vector.h"
35
36 #include <sys/time.h>
37 #include <signal.h>
38
39 #include "wx/unix/private/timer.h"
40
41 #include "wx/listimpl.cpp"
42 WX_DEFINE_LIST(wxTimerList)
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
52 static inline wxString wxUsecClockAsString(wxUsecClock_t usec)
53 {
54 #if wxUSE_LONGLONG
55 return usec.ToString();
56 #else // wxUsecClock_t == double
57 return wxString::Format(wxT("%.0f"), usec);
58 #endif
59 }
60
61 // ============================================================================
62 // wxTimerScheduler implementation
63 // ============================================================================
64
65 wxTimerScheduler *wxTimerScheduler::ms_instance = NULL;
66
67 wxTimerScheduler::~wxTimerScheduler()
68 {
69 for ( wxTimerList::iterator node = m_timers.begin();
70 node != m_timers.end();
71 ++node )
72 {
73 delete *node;
74 }
75 }
76
77 void wxTimerScheduler::AddTimer(wxUnixTimerImpl *timer, wxUsecClock_t expiration)
78 {
79 DoAddTimer(new wxTimerSchedule(timer, expiration));
80 }
81
82 void 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,
89 wxT("adding the same timer twice?") );
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
102 void 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
118 wxFAIL_MSG( wxT("removing inexistent timer?") );
119 }
120
121 bool wxTimerScheduler::GetNext(wxUsecClock_t *remaining) const
122 {
123 if ( m_timers.empty() )
124 return false;
125
126 wxCHECK_MSG( remaining, false, wxT("NULL pointer") );
127
128 *remaining = (*m_timers.begin())->m_expiration - wxGetUTCTimeUSec();
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
138 bool wxTimerScheduler::NotifyExpired()
139 {
140 if ( m_timers.empty() )
141 return false;
142
143 const wxUsecClock_t now = wxGetUTCTimeUSec();
144
145 typedef wxVector<wxUnixTimerImpl *> TimerImpls;
146 TimerImpls toNotify;
147 for ( wxTimerList::iterator next,
148 cur = m_timers.begin(); cur != m_timers.end(); cur = next )
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 {
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
172 // don't need it any more
173 delete s;
174 }
175 else // reschedule the next timer expiration
176 {
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;
182 DoAddTimer(s);
183 }
184
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();
201 }
202
203 return true;
204 }
205
206 // ============================================================================
207 // wxUnixTimerImpl implementation
208 // ============================================================================
209
210 wxUnixTimerImpl::wxUnixTimerImpl(wxTimer* timer)
211 : wxTimerImpl(timer)
212 {
213 m_isRunning = false;
214 }
215
216 bool 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, wxGetUTCTimeUSec() + m_milli*1000);
222 m_isRunning = true;
223
224 return true;
225 }
226
227 void wxUnixTimerImpl::Stop()
228 {
229 if ( m_isRunning )
230 {
231 wxTimerScheduler::Get().RemoveTimer(this);
232
233 m_isRunning = false;
234 }
235 }
236
237 bool wxUnixTimerImpl::IsRunning() const
238 {
239 return m_isRunning;
240 }
241
242 wxUnixTimerImpl::~wxUnixTimerImpl()
243 {
244 wxASSERT_MSG( !m_isRunning, wxT("must have been stopped before") );
245 }
246
247 // ============================================================================
248 // wxTimerUnixModule: responsible for freeing the global timer scheduler
249 // ============================================================================
250
251 class wxTimerUnixModule : public wxModule
252 {
253 public:
254 wxTimerUnixModule() {}
255 virtual bool OnInit() { return true; }
256 virtual void OnExit() { wxTimerScheduler::Shutdown(); }
257
258 DECLARE_DYNAMIC_CLASS(wxTimerUnixModule)
259 };
260
261 IMPLEMENT_DYNAMIC_CLASS(wxTimerUnixModule, wxModule)
262
263 // ============================================================================
264 // global functions
265 // ============================================================================
266
267 wxTimerImpl *wxConsoleAppTraits::CreateTimerImpl(wxTimer *timer)
268 {
269 return new wxUnixTimerImpl(timer);
270 }
271
272 #endif // wxUSE_TIMER
273