wxDFB: use Unix event loop and timers (fixes #10408)
[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 #endif
27
28 #include "wx/thread.h"
29 #include "wx/private/fdiodispatcher.h"
30 #include "wx/dfb/private.h"
31 #include "wx/nonownedwnd.h"
32 #include "wx/buffer.h"
33
34 #define TRACE_EVENTS "events"
35
36 // ===========================================================================
37 // implementation
38 // ===========================================================================
39
40 //-----------------------------------------------------------------------------
41 // wxDFBEventsHandler
42 //-----------------------------------------------------------------------------
43
44 // This handler is installed to process input on DirectFB's events socket (
45 // obtained using CreateFileDescriptor()). When IDirectFBEventBuffer is used
46 // in this mode, events are written to the file descriptor and we read them
47 // in OnReadWaiting() below.
48 class wxDFBEventsHandler : public wxFDIOHandler
49 {
50 public:
51 wxDFBEventsHandler()
52 : m_fd(-1), m_offset(0)
53 {}
54
55 void SetFD(int fd) { m_fd = fd; }
56
57 void Reset()
58 {
59 m_fd = -1;
60 m_offset = 0;
61 }
62
63 // implement wxFDIOHandler pure virtual methods
64 virtual void OnReadWaiting();
65 virtual void OnWriteWaiting()
66 { wxFAIL_MSG("OnWriteWaiting shouldn't be called"); }
67 virtual void OnExceptionWaiting()
68 { wxFAIL_MSG("OnExceptionWaiting shouldn't be called"); }
69
70 private:
71 // DirectFB -> wxWidgets events translation
72 void HandleDFBEvent(const wxDFBEvent& event);
73
74 int m_fd;
75 size_t m_offset;
76 DFBEvent m_event;
77 };
78
79 void wxDFBEventsHandler::OnReadWaiting()
80 {
81 for ( ;; )
82 {
83 int size = read(m_fd,
84 ((char*)&m_event) + m_offset,
85 sizeof(m_event) - m_offset);
86
87 if ( size == 0 || (size == -1 && (errno == EAGAIN || errno == EINTR)) )
88 {
89 // nothing left in the pipe (EAGAIN is expected for an FD with
90 // O_NONBLOCK)
91 break;
92 }
93
94 if ( size == -1 )
95 {
96 wxLogSysError(_("Failed to read event from DirectFB pipe"));
97 break;
98 }
99
100 size += m_offset;
101 m_offset = 0;
102
103 if ( size != sizeof(m_event) )
104 {
105 m_offset = size;
106 break;
107 }
108
109 HandleDFBEvent(m_event);
110 }
111 }
112
113 void wxDFBEventsHandler::HandleDFBEvent(const wxDFBEvent& event)
114 {
115 switch ( event.GetClass() )
116 {
117 case DFEC_WINDOW:
118 {
119 wxDFBWindowEvent winevent(((const DFBEvent&)event).window);
120 wxNonOwnedWindow::HandleDFBWindowEvent(winevent);
121 break;
122 }
123
124 case DFEC_NONE:
125 case DFEC_INPUT:
126 case DFEC_USER:
127 #if wxCHECK_DFB_VERSION(0,9,23)
128 case DFEC_UNIVERSAL:
129 #endif
130 {
131 wxLogTrace(TRACE_EVENTS,
132 "ignoring event of unsupported class %i",
133 (int)event.GetClass());
134 }
135 }
136 }
137
138 //-----------------------------------------------------------------------------
139 // wxEventLoop initialization
140 //-----------------------------------------------------------------------------
141
142 wxIDirectFBEventBufferPtr wxGUIEventLoop::ms_buffer;
143 int wxGUIEventLoop::ms_bufferFd;
144 static wxDFBEventsHandler gs_DFBEventsHandler;
145
146 wxGUIEventLoop::wxGUIEventLoop()
147 {
148 // Note that this has to be done here so that the buffer is ready when
149 // an event loop runs; GetDirectFBEventBuffer(), which also calls
150 // InitBuffer(), may be called before or after the first wxGUIEventLoop
151 // instance is created.
152 if ( !ms_buffer )
153 InitBuffer();
154 }
155
156 /* static */
157 void wxGUIEventLoop::InitBuffer()
158 {
159 // create DirectFB events buffer:
160 ms_buffer = wxIDirectFB::Get()->CreateEventBuffer();
161
162 // and setup a file descriptor that we can watch for new events:
163
164 ms_buffer->CreateFileDescriptor(&ms_bufferFd);
165 int flags = fcntl(ms_bufferFd, F_GETFL, 0);
166 if ( flags == -1 || fcntl(ms_bufferFd, F_SETFL, flags | O_NONBLOCK) == -1 )
167 {
168 wxLogSysError(_("Failed to switch DirectFB pipe to non-blocking mode"));
169 return;
170 }
171
172 wxFDIODispatcher *dispatcher = wxFDIODispatcher::Get();
173 wxCHECK_RET( dispatcher, "wxDFB requires wxFDIODispatcher" );
174
175 gs_DFBEventsHandler.SetFD(ms_bufferFd);
176 dispatcher->RegisterFD(ms_bufferFd, &gs_DFBEventsHandler, wxFDIO_INPUT);
177 }
178
179 /* static */
180 void wxGUIEventLoop::CleanUp()
181 {
182 wxFDIODispatcher *dispatcher = wxFDIODispatcher::Get();
183 wxCHECK_RET( dispatcher, "wxDFB requires wxFDIODispatcher" );
184 dispatcher->UnregisterFD(ms_bufferFd);
185
186 ms_buffer.Reset();
187 gs_DFBEventsHandler.Reset();
188 }
189
190 /* static */
191 wxIDirectFBEventBufferPtr wxGUIEventLoop::GetDirectFBEventBuffer()
192 {
193 if ( !ms_buffer )
194 InitBuffer();
195
196 return ms_buffer;
197 }
198
199 //-----------------------------------------------------------------------------
200 // events dispatch and loop handling
201 //-----------------------------------------------------------------------------
202
203 void wxGUIEventLoop::Yield()
204 {
205 // process all pending events:
206 while ( Pending() )
207 Dispatch();
208
209 // handle timers, sockets etc.
210 OnNextIteration();
211 }