#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 <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 */
-wxIDirectFBEventBufferPtr 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);
- return ms_buffer->HasEvent();
-}
+ 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;
-
- if ( ms_buffer->WaitForEventWithTimeout(0, TIMEOUT) )
+ for ( ;; )
{
- switch ( ms_buffer->GetLastResult() )
+ int size = read(m_fd,
+ ((char*)&m_event) + m_offset,
+ sizeof(m_event) - m_offset);
+
+ if ( size == 0 || (size == -1 && (errno == EAGAIN || errno == EINTR)) )
{
- 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;
+ // nothing left in the pipe (EAGAIN is expected for an FD with
+ // O_NONBLOCK)
+ break;
}
- }
- return true;
-}
+ if ( size == -1 )
+ {
+ wxLogSysError(_("Failed to read event from DirectFB pipe"));
+ break;
+ }
-void wxEventLoop::WakeUp()
-{
- wxCHECK_RET( ms_buffer, _T("invalid event buffer") );
+ size += m_offset;
+ m_offset = 0;
- ms_buffer->WakeUp();
-}
+ 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;
}
#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;
+}