X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b3c861501a451503b31c075ccb59d16b0ae01e99..cbbb1f548962b30c43849e29fd64eceb4d8720e8:/src/dfb/evtloop.cpp diff --git a/src/dfb/evtloop.cpp b/src/dfb/evtloop.cpp index fcfeb0b25c..726ea53b51 100644 --- a/src/dfb/evtloop.cpp +++ b/src/dfb/evtloop.cpp @@ -23,135 +23,219 @@ #ifndef WX_PRECOMP #include "wx/app.h" + #include "wx/log.h" #endif -#include "wx/timer.h" +#include "wx/thread.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 //----------------------------------------------------------------------------- -IDirectFBEventBufferPtr 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() -{ - IDirectFBPtr dfb(wxTheApp->GetDirectFBInterface()); - DFB_CALL( dfb->CreateEventBuffer(dfb, &ms_buffer) ); -} + void SetFD(int fd) { m_fd = fd; } -/* static */ -IDirectFBEventBufferPtr wxEventLoop::GetDirectFBEventBuffer() -{ - if ( !ms_buffer ) - InitBuffer(); - - return ms_buffer; -} + void Reset() + { + m_fd = -1; + m_offset = 0; + } -//----------------------------------------------------------------------------- -// events dispatch and loop handling -//----------------------------------------------------------------------------- + // 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"); } -bool wxEventLoop::Pending() const -{ - wxCHECK_MSG( ms_buffer, false, _T("invalid event buffer") ); +private: + // DirectFB -> wxWidgets events translation + void HandleDFBEvent(const wxDFBEvent& event); - // returns DFB_OK if there is >=1 event, DFB_BUFFER_EMPTY otherwise - return ms_buffer->HasEvent(ms_buffer) == DFB_OK; -} + int m_fd; + size_t m_offset; + DFBEvent m_event; +}; -bool wxEventLoop::Dispatch() +void wxDFBEventsHandler::OnReadWaiting() { - 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 - // - // FIXME: call NotifyTimers() from here (and loop) instead? - const int TIMEOUT = 100; - - DFBResult ret = ms_buffer->WaitForEventWithTimeout(ms_buffer, 0, TIMEOUT); - - switch ( ret ) + for ( ;; ) { - case DFB_OK: + int size = read(m_fd, + ((char*)&m_event) + m_offset, + sizeof(m_event) - m_offset); + + if ( size == 0 || (size == -1 && (errno == EAGAIN || errno == EINTR)) ) { - wxDFBEvent e; - ms_buffer->GetEvent(ms_buffer, &e); - HandleDFBEvent(e); + // nothing left in the pipe (EAGAIN is expected for an FD with + // O_NONBLOCK) break; } - case DFB_TIMEOUT: - // timed out, pretend we processed an event so that OnNextIteration - // is called - break; - - default: - // report any errors, but don't terminate the loop due to them - wxDfbCheckReturn(ret); + if ( size == -1 ) + { + wxLogSysError(_("Failed to read event from DirectFB pipe")); break; - } - - return true; -} + } -void wxEventLoop::WakeUp() -{ - wxCHECK_RET( ms_buffer, _T("invalid event buffer") ); + size += m_offset; + m_offset = 0; - DFB_CALL( ms_buffer->WakeUp(ms_buffer) ); -} + if ( size != sizeof(m_event) ) + { + m_offset = size; + break; + } -void wxEventLoop::OnNextIteration() -{ -#if wxUSE_TIMER - // see the comment in Dispatch - wxTimer::NotifyTimers(); -#endif + HandleDFBEvent(m_event); + } } -#warning "FIXME: cleanup wxEventLoop::ms_buffer before exiting" - - -//----------------------------------------------------------------------------- -// DirectFB -> wxWidgets events translation -//----------------------------------------------------------------------------- - -void wxEventLoop::HandleDFBEvent(const wxDFBEvent& event) +void wxDFBEventsHandler::HandleDFBEvent(const wxDFBEvent& event) { switch ( event.GetClass() ) { case DFEC_WINDOW: { wxDFBWindowEvent winevent(((const DFBEvent&)event).window); - wxTopLevelWindowDFB::HandleDFBWindowEvent(winevent); + 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"), + "ignoring event of unsupported class %i", (int)event.GetClass()); } } } + +//----------------------------------------------------------------------------- +// wxEventLoop initialization +//----------------------------------------------------------------------------- + +wxIDirectFBEventBufferPtr wxGUIEventLoop::ms_buffer; +int wxGUIEventLoop::ms_bufferFd; +static wxDFBEventsHandler gs_DFBEventsHandler; + +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(); +} + +/* static */ +void wxGUIEventLoop::InitBuffer() +{ + // create DirectFB events buffer: + ms_buffer = wxIDirectFB::Get()->CreateEventBuffer(); + + // and setup a file descriptor that we can watch for new events: + + 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 ) + { + wxLogSysError(_("Failed to switch DirectFB pipe to non-blocking mode")); + return; + } + + wxFDIODispatcher *dispatcher = wxFDIODispatcher::Get(); + wxCHECK_RET( dispatcher, "wxDFB requires wxFDIODispatcher" ); + + gs_DFBEventsHandler.SetFD(ms_bufferFd); + dispatcher->RegisterFD(ms_bufferFd, &gs_DFBEventsHandler, wxFDIO_INPUT); +} + +/* static */ +void wxGUIEventLoop::CleanUp() +{ + wxFDIODispatcher *dispatcher = wxFDIODispatcher::Get(); + wxCHECK_RET( dispatcher, "wxDFB requires wxFDIODispatcher" ); + dispatcher->UnregisterFD(ms_bufferFd); + + ms_buffer.Reset(); + gs_DFBEventsHandler.Reset(); +} + +/* static */ +wxIDirectFBEventBufferPtr wxGUIEventLoop::GetDirectFBEventBuffer() +{ + if ( !ms_buffer ) + InitBuffer(); + + return ms_buffer; +} + +//----------------------------------------------------------------------------- +// events dispatch and loop handling +//----------------------------------------------------------------------------- + +bool wxGUIEventLoop::YieldFor(long eventsToProcess) +{ +#if wxUSE_THREADS + if ( !wxThread::IsMain() ) + return true; // can't process events from other threads +#endif // wxUSE_THREADS + + m_isInsideYield = true; + m_eventsToProcessInsideYield = eventsToProcess; + +#if wxUSE_LOG + wxLog::Suspend(); +#endif // wxUSE_LOG + + // TODO: implement event filtering using the eventsToProcess mask + + // process all pending events: + while ( Pending() ) + Dispatch(); + + // handle timers, sockets etc. + OnNextIteration(); + + // it's necessary to call ProcessIdle() to update the frames sizes which + // might have been changed (it also will update other things set from + // OnUpdateUI() which is a nice (and desired) side effect) + while ( ProcessIdle() ) {} + +#if wxUSE_LOG + wxLog::Resume(); +#endif // wxUSE_LOG + + m_isInsideYield = false; + + return true; +}