X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a5001e9361fe01a134b45fa5caf55477e8368d26..c13d6ac1ea199d1e3908d40d129e2fd5a4d82df7:/src/dfb/evtloop.cpp diff --git a/src/dfb/evtloop.cpp b/src/dfb/evtloop.cpp index 9581c327f1..726ea53b51 100644 --- a/src/dfb/evtloop.cpp +++ b/src/dfb/evtloop.cpp @@ -23,13 +23,16 @@ #ifndef WX_PRECOMP #include "wx/app.h" + #include "wx/log.h" #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" + +#include #define TRACE_EVENTS "events" @@ -37,14 +40,118 @@ // implementation // =========================================================================== +//----------------------------------------------------------------------------- +// wxDFBEventsHandler +//----------------------------------------------------------------------------- + +// 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 +{ +public: + wxDFBEventsHandler() + : m_fd(-1), m_offset(0) + {} + + void SetFD(int fd) { m_fd = fd; } + + 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() +{ + 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); + } +} + +void wxDFBEventsHandler::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, + "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(); } @@ -52,13 +159,35 @@ wxGUIEventLoop::wxGUIEventLoop() /* 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 */ @@ -74,113 +203,39 @@ wxIDirectFBEventBufferPtr wxGUIEventLoop::GetDirectFBEventBuffer() // events dispatch and loop handling //----------------------------------------------------------------------------- -bool wxGUIEventLoop::Pending() const -{ - wxCHECK_MSG( ms_buffer, false, "invalid event buffer" ); - - return ms_buffer->HasEvent(); -} - -bool wxGUIEventLoop::Dispatch() -{ - wxCHECK_MSG( ms_buffer, false, "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); - - // and acquire it back before calling any event handlers: - wxMutexGuiEnter(); - - if ( rv ) - { - 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; - } - } - - return true; -} - -void wxGUIEventLoop::WakeUp() +bool wxGUIEventLoop::YieldFor(long eventsToProcess) { - wxCHECK_RET( ms_buffer, "invalid event buffer" ); +#if wxUSE_THREADS + if ( !wxThread::IsMain() ) + return true; // can't process events from other threads +#endif // wxUSE_THREADS - ms_buffer->WakeUp(); -} + m_isInsideYield = true; + m_eventsToProcessInsideYield = eventsToProcess; -void wxGUIEventLoop::OnNextIteration() -{ -#if wxUSE_TIMER - wxGenericTimerImpl::NotifyTimers(); -#endif +#if wxUSE_LOG + wxLog::Suspend(); +#endif // wxUSE_LOG -#if wxUSE_SOCKETS - // handle any pending socket events: - wxSelectDispatcher::DispatchPending(); -#endif -} + // TODO: implement event filtering using the eventsToProcess mask -void wxGUIEventLoop::Yield() -{ // 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() ) {} -//----------------------------------------------------------------------------- -// DirectFB -> wxWidgets events translation -//----------------------------------------------------------------------------- +#if wxUSE_LOG + wxLog::Resume(); +#endif // wxUSE_LOG -void wxGUIEventLoop::HandleDFBEvent(const wxDFBEvent& event) -{ - switch ( event.GetClass() ) - { - case DFEC_WINDOW: - { - wxDFBWindowEvent winevent(((const DFBEvent&)event).window); - wxNonOwnedWindow::HandleDFBWindowEvent(winevent); - break; - } + m_isInsideYield = false; - 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()); - } - } + return true; }