]> git.saurik.com Git - wxWidgets.git/blame - src/unix/evtloopunix.cpp
move default OnInternalIdle processing to wxWindowBase
[wxWidgets.git] / src / unix / evtloopunix.cpp
CommitLineData
b46b1d59
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/unix/evtloopunix.cpp
3// Purpose: wxEventLoop implementation
4// Author: Lukasz Michalski (lm@zork.pl)
5// Created: 2007-05-07
6// RCS-ID: $Id$
7// Copyright: (c) 2006 Zork Lukasz Michalski
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11// ===========================================================================
12// declarations
13// ===========================================================================
14
15// ---------------------------------------------------------------------------
16// headers
17// ---------------------------------------------------------------------------
18
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
a1873279 22#if wxUSE_CONSOLE_EVENTLOOP
b46b1d59 23
1e04d2bf
PC
24#include "wx/evtloop.h"
25
b46b1d59
VZ
26#ifndef WX_PRECOMP
27 #include "wx/app.h"
28 #include "wx/log.h"
29#endif
30
31#include <errno.h>
37ab9399 32#include "wx/apptrait.h"
5cd99866 33#include "wx/scopedptr.h"
b46b1d59
VZ
34#include "wx/thread.h"
35#include "wx/module.h"
3f8cdda4 36#include "wx/unix/pipe.h"
ba752031 37#include "wx/unix/private/timer.h"
b46b1d59
VZ
38#include "wx/unix/private/epolldispatcher.h"
39#include "wx/private/selectdispatcher.h"
40
5cd99866
VZ
41#if wxUSE_EVENTLOOP_SOURCE
42 #include "wx/evtloopsrc.h"
43#endif // wxUSE_EVENTLOOP_SOURCE
44
9a83f860 45#define TRACE_EVENTS wxT("events")
b46b1d59
VZ
46
47// ===========================================================================
48// wxEventLoop::PipeIOHandler implementation
49// ===========================================================================
50
3f8cdda4
VS
51namespace wxPrivate
52{
53
54// pipe used for wake up messages: when a child thread wants to wake up
55// the event loop in the main thread it writes to this pipe
56class PipeIOHandler : public wxFDIOHandler
57{
58public:
59 // default ctor does nothing, call Create() to really initialize the
60 // object
61 PipeIOHandler() { }
62
63 bool Create();
64
65 // this method can be, and normally is, called from another thread
66 void WakeUp();
67
68 int GetReadFd() { return m_pipe[wxPipe::Read]; }
69
70 // implement wxFDIOHandler pure virtual methods
71 virtual void OnReadWaiting();
72 virtual void OnWriteWaiting() { }
73 virtual void OnExceptionWaiting() { }
74
75private:
76 wxPipe m_pipe;
77};
78
b46b1d59
VZ
79// ----------------------------------------------------------------------------
80// initialization
81// ----------------------------------------------------------------------------
82
3f8cdda4 83bool PipeIOHandler::Create()
b46b1d59
VZ
84{
85 if ( !m_pipe.Create() )
86 {
87 wxLogError(_("Failed to create wake up pipe used by event loop."));
88 return false;
89 }
90
b8353201 91 if ( !m_pipe.MakeNonBlocking(wxPipe::Read) )
b46b1d59
VZ
92 {
93 wxLogSysError(_("Failed to switch wake up pipe to non-blocking mode"));
94 return false;
95 }
96
97 wxLogTrace(TRACE_EVENTS, wxT("Wake up pipe (%d, %d) created"),
b8353201 98 m_pipe[wxPipe::Read], m_pipe[wxPipe::Write]);
b46b1d59
VZ
99
100 return true;
101}
102
103// ----------------------------------------------------------------------------
104// wakeup handling
105// ----------------------------------------------------------------------------
106
3f8cdda4 107void PipeIOHandler::WakeUp()
b46b1d59
VZ
108{
109 if ( write(m_pipe[wxPipe::Write], "s", 1) != 1 )
110 {
111 // don't use wxLog here, we can be in another thread and this could
112 // result in dead locks
113 perror("write(wake up pipe)");
114 }
115}
116
3f8cdda4 117void PipeIOHandler::OnReadWaiting()
b46b1d59
VZ
118{
119 // got wakeup from child thread: read all data available in pipe just to
a12698ab 120 // make it empty (even though we write one byte at a time from WakeUp(),
b46b1d59
VZ
121 // it could have been called several times)
122 char buf[4];
123 for ( ;; )
124 {
125 const int size = read(GetReadFd(), buf, WXSIZEOF(buf));
126
fada8bef 127 if ( size == 0 || (size == -1 && (errno == EAGAIN || errno == EINTR)) )
b46b1d59
VZ
128 {
129 // nothing left in the pipe (EAGAIN is expected for an FD with
130 // O_NONBLOCK)
131 break;
132 }
133
134 if ( size == -1 )
135 {
136 wxLogSysError(_("Failed to read from wake-up pipe"));
137
138 break;
139 }
140 }
141
a12698ab
VZ
142 // writing to the wake up pipe will make wxConsoleEventLoop return from
143 // wxFDIODispatcher::Dispatch() it might be currently blocking in, nothing
144 // else needs to be done
b46b1d59
VZ
145}
146
3f8cdda4
VS
147} // namespace wxPrivate
148
b46b1d59
VZ
149// ===========================================================================
150// wxEventLoop implementation
151// ===========================================================================
152
153//-----------------------------------------------------------------------------
154// initialization
155//-----------------------------------------------------------------------------
156
157wxConsoleEventLoop::wxConsoleEventLoop()
158{
3f8cdda4
VS
159 m_wakeupPipe = new wxPrivate::PipeIOHandler();
160 if ( !m_wakeupPipe->Create() )
b46b1d59 161 {
3f8cdda4 162 wxDELETE(m_wakeupPipe);
b46b1d59
VZ
163 m_dispatcher = NULL;
164 return;
165 }
166
5e1eac14 167 m_dispatcher = wxFDIODispatcher::Get();
b46b1d59 168 if ( !m_dispatcher )
5e1eac14 169 return;
b46b1d59
VZ
170
171 m_dispatcher->RegisterFD
172 (
3f8cdda4
VS
173 m_wakeupPipe->GetReadFd(),
174 m_wakeupPipe,
b46b1d59
VZ
175 wxFDIO_INPUT
176 );
3ef595d5 177}
b46b1d59 178
3f8cdda4
VS
179wxConsoleEventLoop::~wxConsoleEventLoop()
180{
c8299fa8
VZ
181 if ( m_wakeupPipe )
182 {
183 if ( m_dispatcher )
184 {
185 m_dispatcher->UnregisterFD(m_wakeupPipe->GetReadFd());
186 }
187
188 delete m_wakeupPipe;
189 }
3f8cdda4
VS
190}
191
6b8ef0b3
VZ
192//-----------------------------------------------------------------------------
193// adding & removing sources
194//-----------------------------------------------------------------------------
195
196#if wxUSE_EVENTLOOP_SOURCE
197
198// This class is a temporary bridge between event loop sources and
199// FDIODispatcher. It is going to be removed soon, when all subject interfaces
200// are modified
201class wxFDIOEventLoopSourceHandler : public wxFDIOHandler
202{
203public:
204 wxFDIOEventLoopSourceHandler(wxEventLoopSourceHandler* handler) :
205 m_impl(handler) { }
206
207 virtual void OnReadWaiting()
208 {
209 m_impl->OnReadWaiting();
210 }
211 virtual void OnWriteWaiting()
212 {
213 m_impl->OnWriteWaiting();
214 }
215
216 virtual void OnExceptionWaiting()
217 {
218 m_impl->OnExceptionWaiting();
219 }
220
221protected:
222 wxEventLoopSourceHandler* m_impl;
223};
224
5cd99866
VZ
225wxEventLoopSource *
226wxConsoleEventLoop::AddSourceForFD(int fd,
227 wxEventLoopSourceHandler *handler,
228 int flags)
6b8ef0b3 229{
5cd99866 230 wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" );
6b8ef0b3
VZ
231
232 wxLogTrace(wxTRACE_EVT_SOURCE,
5cd99866 233 "Adding event loop source for fd=%d", fd);
6b8ef0b3 234
5cd99866
VZ
235 // we need a bridge to wxFDIODispatcher
236 //
237 // TODO: refactor the code so that only wxEventLoopSourceHandler is used
238 wxScopedPtr<wxFDIOHandler>
239 fdioHandler(new wxFDIOEventLoopSourceHandler(handler));
6b8ef0b3 240
5cd99866
VZ
241 if ( !m_dispatcher->RegisterFD(fd, fdioHandler.get(), flags) )
242 return NULL;
243
244 return new wxUnixEventLoopSource(m_dispatcher, fdioHandler.release(),
245 fd, handler, flags);
6b8ef0b3
VZ
246}
247
5cd99866 248wxUnixEventLoopSource::~wxUnixEventLoopSource()
6b8ef0b3 249{
6b8ef0b3 250 wxLogTrace(wxTRACE_EVT_SOURCE,
5cd99866 251 "Removing event loop source for fd=%d", m_fd);
6b8ef0b3 252
5cd99866
VZ
253 m_dispatcher->UnregisterFD(m_fd);
254
255 delete m_fdioHandler;
6b8ef0b3 256}
5cd99866
VZ
257
258#endif // wxUSE_EVENTLOOP_SOURCE
6b8ef0b3 259
b46b1d59
VZ
260//-----------------------------------------------------------------------------
261// events dispatch and loop handling
262//-----------------------------------------------------------------------------
263
264bool wxConsoleEventLoop::Pending() const
265{
a12698ab
VZ
266 if ( m_dispatcher->HasPending() )
267 return true;
268
269#if wxUSE_TIMER
270 wxUsecClock_t nextTimer;
271 if ( wxTimerScheduler::Get().GetNext(&nextTimer) &&
272 !wxMilliClockToLong(nextTimer) )
273 return true;
274#endif // wxUSE_TIMER
275
276 return false;
b46b1d59
VZ
277}
278
279bool wxConsoleEventLoop::Dispatch()
b46b1d59 280{
c22ace4d
VZ
281 DispatchTimeout(static_cast<unsigned long>(
282 wxFDIODispatcher::TIMEOUT_INFINITE));
b46b1d59 283
9af42efd
VZ
284 return true;
285}
286
287int wxConsoleEventLoop::DispatchTimeout(unsigned long timeout)
288{
b46b1d59 289#if wxUSE_TIMER
9af42efd 290 // check if we need to decrease the timeout to account for a timer
b46b1d59
VZ
291 wxUsecClock_t nextTimer;
292 if ( wxTimerScheduler::Get().GetNext(&nextTimer) )
293 {
9af42efd
VZ
294 unsigned long timeUntilNextTimer = wxMilliClockToLong(nextTimer / 1000);
295 if ( timeUntilNextTimer < timeout )
296 timeout = timeUntilNextTimer;
b46b1d59 297 }
b46b1d59 298#endif // wxUSE_TIMER
b46b1d59 299
a12698ab 300 bool hadEvent = m_dispatcher->Dispatch(timeout) > 0;
b46b1d59
VZ
301
302#if wxUSE_TIMER
9af42efd
VZ
303 if ( wxTimerScheduler::Get().NotifyExpired() )
304 hadEvent = true;
305#endif // wxUSE_TIMER
b46b1d59 306
9af42efd 307 return hadEvent ? 1 : -1;
438febca
VZ
308}
309
310void wxConsoleEventLoop::WakeUp()
311{
3f8cdda4 312 m_wakeupPipe->WakeUp();
438febca
VZ
313}
314
315void wxConsoleEventLoop::OnNextIteration()
316{
b46b1d59
VZ
317 // call the signal handlers for any signals we caught recently
318 wxTheApp->CheckSignal();
319}
320
37ab9399
SN
321
322wxEventLoopBase *wxConsoleAppTraits::CreateEventLoop()
323{
324 return new wxEventLoop();
325}
326
a1873279 327#endif // wxUSE_CONSOLE_EVENTLOOP