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