X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c2ca375c5620209d77a88d2d378bdcdedbc82e7e..bcf324bebe65cd7ee49c139533ceea52dceb4b91:/src/dfb/evtloop.cpp diff --git a/src/dfb/evtloop.cpp b/src/dfb/evtloop.cpp index 16a348110b..d18b73a251 100644 --- a/src/dfb/evtloop.cpp +++ b/src/dfb/evtloop.cpp @@ -26,127 +26,186 @@ #endif #include "wx/thread.h" -#include "wx/generic/private/timer.h" -#include "wx/private/selectdispatcher.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 + +#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 - wxGenericTimerImpl::NotifyTimers(); -#endif + if ( !ms_buffer ) + InitBuffer(); -#if wxUSE_SOCKETS - // handle any pending socket events: - wxSelectDispatcher::Get().RunLoop(0); -#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(); @@ -154,33 +213,3 @@ void wxEventLoop::Yield() // 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()); - } - } -}