non-pch build fix
[wxWidgets.git] / src / dfb / evtloop.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/dfb/evtloop.cpp
3 // Purpose: wxEventLoop implementation
4 // Author: Vaclav Slavik
5 // Created: 2006-08-16
6 // RCS-ID: $Id$
7 // Copyright: (c) 2006 REA Elektronik GmbH
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
22 #include "wx/evtloop.h"
23
24 #ifndef WX_PRECOMP
25 #include "wx/app.h"
26 #include "wx/log.h"
27 #endif
28
29 #include "wx/thread.h"
30 #include "wx/private/fdiodispatcher.h"
31 #include "wx/dfb/private.h"
32 #include "wx/nonownedwnd.h"
33 #include "wx/buffer.h"
34
35 #include <errno.h>
36
37 #define TRACE_EVENTS "events"
38
39 // ===========================================================================
40 // implementation
41 // ===========================================================================
42
43 //-----------------------------------------------------------------------------
44 // wxDFBEventsHandler
45 //-----------------------------------------------------------------------------
46
47 // This handler is installed to process input on DirectFB's events socket (
48 // obtained using CreateFileDescriptor()). When IDirectFBEventBuffer is used
49 // in this mode, events are written to the file descriptor and we read them
50 // in OnReadWaiting() below.
51 class wxDFBEventsHandler : public wxFDIOHandler
52 {
53 public:
54 wxDFBEventsHandler()
55 : m_fd(-1), m_offset(0)
56 {}
57
58 void SetFD(int fd) { m_fd = fd; }
59
60 void Reset()
61 {
62 m_fd = -1;
63 m_offset = 0;
64 }
65
66 // implement wxFDIOHandler pure virtual methods
67 virtual void OnReadWaiting();
68 virtual void OnWriteWaiting()
69 { wxFAIL_MSG("OnWriteWaiting shouldn't be called"); }
70 virtual void OnExceptionWaiting()
71 { wxFAIL_MSG("OnExceptionWaiting shouldn't be called"); }
72
73 private:
74 // DirectFB -> wxWidgets events translation
75 void HandleDFBEvent(const wxDFBEvent& event);
76
77 int m_fd;
78 size_t m_offset;
79 DFBEvent m_event;
80 };
81
82 void wxDFBEventsHandler::OnReadWaiting()
83 {
84 for ( ;; )
85 {
86 int size = read(m_fd,
87 ((char*)&m_event) + m_offset,
88 sizeof(m_event) - m_offset);
89
90 if ( size == 0 || (size == -1 && (errno == EAGAIN || errno == EINTR)) )
91 {
92 // nothing left in the pipe (EAGAIN is expected for an FD with
93 // O_NONBLOCK)
94 break;
95 }
96
97 if ( size == -1 )
98 {
99 wxLogSysError(_("Failed to read event from DirectFB pipe"));
100 break;
101 }
102
103 size += m_offset;
104 m_offset = 0;
105
106 if ( size != sizeof(m_event) )
107 {
108 m_offset = size;
109 break;
110 }
111
112 HandleDFBEvent(m_event);
113 }
114 }
115
116 void wxDFBEventsHandler::HandleDFBEvent(const wxDFBEvent& event)
117 {
118 switch ( event.GetClass() )
119 {
120 case DFEC_WINDOW:
121 {
122 wxDFBWindowEvent winevent(((const DFBEvent&)event).window);
123 wxNonOwnedWindow::HandleDFBWindowEvent(winevent);
124 break;
125 }
126
127 case DFEC_NONE:
128 case DFEC_INPUT:
129 case DFEC_USER:
130 #if wxCHECK_DFB_VERSION(0,9,23)
131 case DFEC_UNIVERSAL:
132 #endif
133 {
134 wxLogTrace(TRACE_EVENTS,
135 "ignoring event of unsupported class %i",
136 (int)event.GetClass());
137 }
138 }
139 }
140
141 //-----------------------------------------------------------------------------
142 // wxEventLoop initialization
143 //-----------------------------------------------------------------------------
144
145 wxIDirectFBEventBufferPtr wxGUIEventLoop::ms_buffer;
146 int wxGUIEventLoop::ms_bufferFd;
147 static wxDFBEventsHandler gs_DFBEventsHandler;
148
149 wxGUIEventLoop::wxGUIEventLoop()
150 {
151 // Note that this has to be done here so that the buffer is ready when
152 // an event loop runs; GetDirectFBEventBuffer(), which also calls
153 // InitBuffer(), may be called before or after the first wxGUIEventLoop
154 // instance is created.
155 if ( !ms_buffer )
156 InitBuffer();
157 }
158
159 /* static */
160 void wxGUIEventLoop::InitBuffer()
161 {
162 // create DirectFB events buffer:
163 ms_buffer = wxIDirectFB::Get()->CreateEventBuffer();
164
165 // and setup a file descriptor that we can watch for new events:
166
167 ms_buffer->CreateFileDescriptor(&ms_bufferFd);
168 int flags = fcntl(ms_bufferFd, F_GETFL, 0);
169 if ( flags == -1 || fcntl(ms_bufferFd, F_SETFL, flags | O_NONBLOCK) == -1 )
170 {
171 wxLogSysError(_("Failed to switch DirectFB pipe to non-blocking mode"));
172 return;
173 }
174
175 wxFDIODispatcher *dispatcher = wxFDIODispatcher::Get();
176 wxCHECK_RET( dispatcher, "wxDFB requires wxFDIODispatcher" );
177
178 gs_DFBEventsHandler.SetFD(ms_bufferFd);
179 dispatcher->RegisterFD(ms_bufferFd, &gs_DFBEventsHandler, wxFDIO_INPUT);
180 }
181
182 /* static */
183 void wxGUIEventLoop::CleanUp()
184 {
185 wxFDIODispatcher *dispatcher = wxFDIODispatcher::Get();
186 wxCHECK_RET( dispatcher, "wxDFB requires wxFDIODispatcher" );
187 dispatcher->UnregisterFD(ms_bufferFd);
188
189 ms_buffer.Reset();
190 gs_DFBEventsHandler.Reset();
191 }
192
193 /* static */
194 wxIDirectFBEventBufferPtr wxGUIEventLoop::GetDirectFBEventBuffer()
195 {
196 if ( !ms_buffer )
197 InitBuffer();
198
199 return ms_buffer;
200 }
201
202 //-----------------------------------------------------------------------------
203 // events dispatch and loop handling
204 //-----------------------------------------------------------------------------
205
206 bool wxGUIEventLoop::YieldFor(long eventsToProcess)
207 {
208 #if wxUSE_THREADS
209 if ( !wxThread::IsMain() )
210 return true; // can't process events from other threads
211 #endif // wxUSE_THREADS
212
213 m_isInsideYield = true;
214 m_eventsToProcessInsideYield = eventsToProcess;
215
216 #if wxUSE_LOG
217 wxLog::Suspend();
218 #endif // wxUSE_LOG
219
220 // TODO: implement event filtering using the eventsToProcess mask
221
222 // process all pending events:
223 while ( Pending() )
224 Dispatch();
225
226 // handle timers, sockets etc.
227 OnNextIteration();
228
229 // it's necessary to call ProcessIdle() to update the frames sizes which
230 // might have been changed (it also will update other things set from
231 // OnUpdateUI() which is a nice (and desired) side effect)
232 while ( ProcessIdle() ) {}
233
234 #if wxUSE_LOG
235 wxLog::Resume();
236 #endif // wxUSE_LOG
237
238 m_isInsideYield = false;
239
240 return true;
241 }