#endif
#include "wx/thread.h"
-#include "wx/timer.h"
-#include "wx/private/socketevtdispatch.h"
+#include "wx/private/fdiodispatcher.h"
#include "wx/dfb/private.h"
#include "wx/nonownedwnd.h"
+#include "wx/buffer.h"
-#define TRACE_EVENTS _T("events")
+#include <errno.h>
+
+#define TRACE_EVENTS "events"
// ===========================================================================
// implementation
// ===========================================================================
//-----------------------------------------------------------------------------
-// wxEventLoop initialization
+// wxDFBEventsHandler
//-----------------------------------------------------------------------------
-wxIDirectFBEventBufferPtr wxEventLoop::ms_buffer;
-
-wxEventLoop::wxEventLoop()
+// This handler is installed to process input on DirectFB's events socket (
+// obtained using CreateFileDescriptor()). When IDirectFBEventBuffer is used
+// in this mode, events are written to the file descriptor and we read them
+// in OnReadWaiting() below.
+class wxDFBEventsHandler : public wxFDIOHandler
{
- if ( !ms_buffer )
- InitBuffer();
-}
+public:
+ wxDFBEventsHandler()
+ : m_fd(-1), m_offset(0)
+ {}
-/* static */
-void wxEventLoop::InitBuffer()
-{
- ms_buffer = wxIDirectFB::Get()->CreateEventBuffer();
-}
+ void SetFD(int fd) { m_fd = fd; }
-/* static */
-void wxEventLoop::CleanUp()
+ void Reset()
+ {
+ m_fd = -1;
+ m_offset = 0;
+ }
+
+ // implement wxFDIOHandler pure virtual methods
+ virtual void OnReadWaiting();
+ virtual void OnWriteWaiting()
+ { wxFAIL_MSG("OnWriteWaiting shouldn't be called"); }
+ virtual void OnExceptionWaiting()
+ { wxFAIL_MSG("OnExceptionWaiting shouldn't be called"); }
+
+private:
+ // DirectFB -> wxWidgets events translation
+ void HandleDFBEvent(const wxDFBEvent& event);
+
+ int m_fd;
+ size_t m_offset;
+ DFBEvent m_event;
+};
+
+void wxDFBEventsHandler::OnReadWaiting()
{
- ms_buffer.Reset();
+ for ( ;; )
+ {
+ int size = read(m_fd,
+ ((char*)&m_event) + m_offset,
+ sizeof(m_event) - m_offset);
+
+ if ( size == 0 || (size == -1 && (errno == EAGAIN || errno == EINTR)) )
+ {
+ // nothing left in the pipe (EAGAIN is expected for an FD with
+ // O_NONBLOCK)
+ break;
+ }
+
+ if ( size == -1 )
+ {
+ wxLogSysError(_("Failed to read event from DirectFB pipe"));
+ break;
+ }
+
+ size += m_offset;
+ m_offset = 0;
+
+ if ( size != sizeof(m_event) )
+ {
+ m_offset = size;
+ break;
+ }
+
+ HandleDFBEvent(m_event);
+ }
}
-/* static */
-wxIDirectFBEventBufferPtr wxEventLoop::GetDirectFBEventBuffer()
+void wxDFBEventsHandler::HandleDFBEvent(const wxDFBEvent& event)
{
- if ( !ms_buffer )
- InitBuffer();
+ switch ( event.GetClass() )
+ {
+ case DFEC_WINDOW:
+ {
+ wxDFBWindowEvent winevent(((const DFBEvent&)event).window);
+ wxNonOwnedWindow::HandleDFBWindowEvent(winevent);
+ break;
+ }
- return ms_buffer;
+ case DFEC_NONE:
+ case DFEC_INPUT:
+ case DFEC_USER:
+#if wxCHECK_DFB_VERSION(0,9,23)
+ case DFEC_UNIVERSAL:
+#endif
+ {
+ wxLogTrace(TRACE_EVENTS,
+ "ignoring event of unsupported class %i",
+ (int)event.GetClass());
+ }
+ }
}
//-----------------------------------------------------------------------------
-// events dispatch and loop handling
+// wxEventLoop initialization
//-----------------------------------------------------------------------------
-bool wxEventLoop::Pending() const
-{
- wxCHECK_MSG( ms_buffer, false, _T("invalid event buffer") );
+wxIDirectFBEventBufferPtr wxGUIEventLoop::ms_buffer;
+int wxGUIEventLoop::ms_bufferFd;
+static wxDFBEventsHandler gs_DFBEventsHandler;
- return ms_buffer->HasEvent();
+wxGUIEventLoop::wxGUIEventLoop()
+{
+ // Note that this has to be done here so that the buffer is ready when
+ // an event loop runs; GetDirectFBEventBuffer(), which also calls
+ // InitBuffer(), may be called before or after the first wxGUIEventLoop
+ // instance is created.
+ if ( !ms_buffer )
+ InitBuffer();
}
-bool wxEventLoop::Dispatch()
+/* static */
+void wxGUIEventLoop::InitBuffer()
{
- wxCHECK_MSG( ms_buffer, false, _T("invalid event buffer") );
-
- // NB: we don't block indefinitely waiting for an event, but instead
- // time out after a brief period in order to make sure that
- // OnNextIteration() will be called frequently enough
- const int TIMEOUT = 100;
-
- // release the GUI mutex so that other threads have a chance to post
- // events:
- wxMutexGuiLeave();
-
- bool rv = ms_buffer->WaitForEventWithTimeout(0, TIMEOUT);
+ // create DirectFB events buffer:
+ ms_buffer = wxIDirectFB::Get()->CreateEventBuffer();
- // and acquire it back before calling any event handlers:
- wxMutexGuiEnter();
+ // and setup a file descriptor that we can watch for new events:
- if ( rv )
+ ms_buffer->CreateFileDescriptor(&ms_bufferFd);
+ int flags = fcntl(ms_bufferFd, F_GETFL, 0);
+ if ( flags == -1 || fcntl(ms_bufferFd, F_SETFL, flags | O_NONBLOCK) == -1 )
{
- switch ( ms_buffer->GetLastResult() )
- {
- case DFB_OK:
- {
- wxDFBEvent e;
- ms_buffer->GetEvent(e);
- HandleDFBEvent(e);
- break;
- }
-
- case DFB_TIMEOUT:
- // timed out, pretend we processed an event so that
- // OnNextIteration is called
- break;
-
- default:
- // don't terminate the loop due to errors (they were reported
- // already by ms_buffer)
- break;
- }
+ wxLogSysError(_("Failed to switch DirectFB pipe to non-blocking mode"));
+ return;
}
- return true;
+ wxFDIODispatcher *dispatcher = wxFDIODispatcher::Get();
+ wxCHECK_RET( dispatcher, "wxDFB requires wxFDIODispatcher" );
+
+ gs_DFBEventsHandler.SetFD(ms_bufferFd);
+ dispatcher->RegisterFD(ms_bufferFd, &gs_DFBEventsHandler, wxFDIO_INPUT);
}
-void wxEventLoop::WakeUp()
+/* static */
+void wxGUIEventLoop::CleanUp()
{
- wxCHECK_RET( ms_buffer, _T("invalid event buffer") );
+ wxFDIODispatcher *dispatcher = wxFDIODispatcher::Get();
+ wxCHECK_RET( dispatcher, "wxDFB requires wxFDIODispatcher" );
+ dispatcher->UnregisterFD(ms_bufferFd);
- ms_buffer->WakeUp();
+ ms_buffer.Reset();
+ gs_DFBEventsHandler.Reset();
}
-void wxEventLoop::OnNextIteration()
+/* static */
+wxIDirectFBEventBufferPtr wxGUIEventLoop::GetDirectFBEventBuffer()
{
-#if wxUSE_TIMER
- wxTimer::NotifyTimers();
-#endif
+ if ( !ms_buffer )
+ InitBuffer();
-#if wxUSE_SOCKETS
- // handle any pending socket events:
- wxSocketEventDispatcher::Get().RunLoop();
-#endif
+ return ms_buffer;
}
-void wxEventLoop::Yield()
+//-----------------------------------------------------------------------------
+// events dispatch and loop handling
+//-----------------------------------------------------------------------------
+
+void wxGUIEventLoop::Yield()
{
+ // TODO: implement event filtering using the eventsToProcess mask
+
// process all pending events:
while ( Pending() )
Dispatch();
// handle timers, sockets etc.
OnNextIteration();
}
-
-
-//-----------------------------------------------------------------------------
-// DirectFB -> wxWidgets events translation
-//-----------------------------------------------------------------------------
-
-void wxEventLoop::HandleDFBEvent(const wxDFBEvent& event)
-{
- switch ( event.GetClass() )
- {
- case DFEC_WINDOW:
- {
- wxDFBWindowEvent winevent(((const DFBEvent&)event).window);
- wxNonOwnedWindow::HandleDFBWindowEvent(winevent);
- break;
- }
-
- case DFEC_NONE:
- case DFEC_INPUT:
- case DFEC_USER:
-#if wxCHECK_DFB_VERSION(0,9,23)
- case DFEC_UNIVERSAL:
-#endif
- {
- wxLogTrace(TRACE_EVENTS,
- _T("ignoring event of unsupported class %i"),
- (int)event.GetClass());
- }
- }
-}