From 86e9b8f28fc8db834628e1528e12f3eeb1f6e216 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= Date: Fri, 30 Jan 2009 15:21:47 +0000 Subject: [PATCH] wxDFB: use Unix event loop and timers (fixes #10408) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58520 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- Makefile.in | 20 --- build/bakefiles/files.bkl | 1 - include/wx/dfb/chkconf.h | 6 +- include/wx/dfb/evtloop.h | 19 +-- include/wx/dfb/nonownedwnd.h | 5 +- include/wx/dfb/wrapdfb.h | 34 +---- include/wx/unix/private/timer.h | 4 +- src/dfb/evtloop.cpp | 237 +++++++++++++++++--------------- src/dfb/utils.cpp | 6 + 9 files changed, 149 insertions(+), 183 deletions(-) diff --git a/Makefile.in b/Makefile.in index 2f952b9ffe..fd4fa5affb 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4363,7 +4363,6 @@ COND_TOOLKIT_DFB___LOWLEVEL_SRC_OBJECTS = \ monodll_generic_icon.o \ monodll_generic_imaglist.o \ monodll_mask.o \ - monodll_generic_timer.o \ monodll_dfb_app.o \ monodll_dfb_bitmap.o \ monodll_dfb_brush.o \ @@ -5227,7 +5226,6 @@ COND_TOOLKIT_DFB___LOWLEVEL_SRC_OBJECTS_1 = \ monodll_generic_icon.o \ monodll_generic_imaglist.o \ monodll_mask.o \ - monodll_generic_timer.o \ monodll_dfb_app.o \ monodll_dfb_bitmap.o \ monodll_dfb_brush.o \ @@ -6176,7 +6174,6 @@ COND_TOOLKIT_DFB___LOWLEVEL_SRC_OBJECTS_2 = \ monolib_generic_icon.o \ monolib_generic_imaglist.o \ monolib_mask.o \ - monolib_generic_timer.o \ monolib_dfb_app.o \ monolib_dfb_bitmap.o \ monolib_dfb_brush.o \ @@ -7040,7 +7037,6 @@ COND_TOOLKIT_DFB___LOWLEVEL_SRC_OBJECTS_3 = \ monolib_generic_icon.o \ monolib_generic_imaglist.o \ monolib_mask.o \ - monolib_generic_timer.o \ monolib_dfb_app.o \ monolib_dfb_bitmap.o \ monolib_dfb_brush.o \ @@ -8135,7 +8131,6 @@ COND_TOOLKIT_DFB___LOWLEVEL_SRC_OBJECTS_4 = \ coredll_generic_icon.o \ coredll_generic_imaglist.o \ coredll_mask.o \ - coredll_generic_timer.o \ coredll_dfb_app.o \ coredll_dfb_bitmap.o \ coredll_dfb_brush.o \ @@ -8999,7 +8994,6 @@ COND_TOOLKIT_DFB___LOWLEVEL_SRC_OBJECTS_5 = \ coredll_generic_icon.o \ coredll_generic_imaglist.o \ coredll_mask.o \ - coredll_generic_timer.o \ coredll_dfb_app.o \ coredll_dfb_bitmap.o \ coredll_dfb_brush.o \ @@ -9646,7 +9640,6 @@ COND_TOOLKIT_DFB___LOWLEVEL_SRC_OBJECTS_6 = \ corelib_generic_icon.o \ corelib_generic_imaglist.o \ corelib_mask.o \ - corelib_generic_timer.o \ corelib_dfb_app.o \ corelib_dfb_bitmap.o \ corelib_dfb_brush.o \ @@ -10510,7 +10503,6 @@ COND_TOOLKIT_DFB___LOWLEVEL_SRC_OBJECTS_7 = \ corelib_generic_icon.o \ corelib_generic_imaglist.o \ corelib_mask.o \ - corelib_generic_timer.o \ corelib_dfb_app.o \ corelib_dfb_bitmap.o \ corelib_dfb_brush.o \ @@ -16944,9 +16936,6 @@ monodll_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONODLL_ODEP) @COND_TOOLKIT_MGL_USE_GUI_1@monodll_generic_timer.o: $(srcdir)/src/generic/timer.cpp $(MONODLL_ODEP) @COND_TOOLKIT_MGL_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/generic/timer.cpp -@COND_TOOLKIT_DFB_USE_GUI_1@monodll_generic_timer.o: $(srcdir)/src/generic/timer.cpp $(MONODLL_ODEP) -@COND_TOOLKIT_DFB_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/generic/timer.cpp - @COND_TOOLKIT_X11_USE_GUI_1@monodll_x11_app.o: $(srcdir)/src/x11/app.cpp $(MONODLL_ODEP) @COND_TOOLKIT_X11_USE_GUI_1@ $(CXXC) -c -o $@ $(MONODLL_CXXFLAGS) $(srcdir)/src/x11/app.cpp @@ -21615,9 +21604,6 @@ monolib_sound_sdl.o: $(srcdir)/src/unix/sound_sdl.cpp $(MONOLIB_ODEP) @COND_TOOLKIT_MGL_USE_GUI_1@monolib_generic_timer.o: $(srcdir)/src/generic/timer.cpp $(MONOLIB_ODEP) @COND_TOOLKIT_MGL_USE_GUI_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/generic/timer.cpp -@COND_TOOLKIT_DFB_USE_GUI_1@monolib_generic_timer.o: $(srcdir)/src/generic/timer.cpp $(MONOLIB_ODEP) -@COND_TOOLKIT_DFB_USE_GUI_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/generic/timer.cpp - @COND_TOOLKIT_X11_USE_GUI_1@monolib_x11_app.o: $(srcdir)/src/x11/app.cpp $(MONOLIB_ODEP) @COND_TOOLKIT_X11_USE_GUI_1@ $(CXXC) -c -o $@ $(MONOLIB_CXXFLAGS) $(srcdir)/src/x11/app.cpp @@ -26469,9 +26455,6 @@ coredll_win32.o: $(srcdir)/src/univ/themes/win32.cpp $(COREDLL_ODEP) @COND_TOOLKIT_MGL_USE_GUI_1@coredll_generic_timer.o: $(srcdir)/src/generic/timer.cpp $(COREDLL_ODEP) @COND_TOOLKIT_MGL_USE_GUI_1@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/generic/timer.cpp -@COND_TOOLKIT_DFB_USE_GUI_1@coredll_generic_timer.o: $(srcdir)/src/generic/timer.cpp $(COREDLL_ODEP) -@COND_TOOLKIT_DFB_USE_GUI_1@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/generic/timer.cpp - @COND_TOOLKIT_X11_USE_GUI_1@coredll_x11_app.o: $(srcdir)/src/x11/app.cpp $(COREDLL_ODEP) @COND_TOOLKIT_X11_USE_GUI_1@ $(CXXC) -c -o $@ $(COREDLL_CXXFLAGS) $(srcdir)/src/x11/app.cpp @@ -29970,9 +29953,6 @@ corelib_win32.o: $(srcdir)/src/univ/themes/win32.cpp $(CORELIB_ODEP) @COND_TOOLKIT_MGL_USE_GUI_1@corelib_generic_timer.o: $(srcdir)/src/generic/timer.cpp $(CORELIB_ODEP) @COND_TOOLKIT_MGL_USE_GUI_1@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/generic/timer.cpp -@COND_TOOLKIT_DFB_USE_GUI_1@corelib_generic_timer.o: $(srcdir)/src/generic/timer.cpp $(CORELIB_ODEP) -@COND_TOOLKIT_DFB_USE_GUI_1@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/generic/timer.cpp - @COND_TOOLKIT_X11_USE_GUI_1@corelib_x11_app.o: $(srcdir)/src/x11/app.cpp $(CORELIB_ODEP) @COND_TOOLKIT_X11_USE_GUI_1@ $(CXXC) -c -o $@ $(CORELIB_CXXFLAGS) $(srcdir)/src/x11/app.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index cd4598a3b8..9db7573006 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -1916,7 +1916,6 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/generic/icon.cpp src/generic/imaglist.cpp src/generic/mask.cpp - src/generic/timer.cpp src/dfb/app.cpp src/dfb/bitmap.cpp src/dfb/brush.cpp diff --git a/include/wx/dfb/chkconf.h b/include/wx/dfb/chkconf.h index cbc9e7f331..6e2895a16a 100644 --- a/include/wx/dfb/chkconf.h +++ b/include/wx/dfb/chkconf.h @@ -21,12 +21,12 @@ # error "wxFileConfig is required by wxDFB port" #endif -#if wxUSE_SOCKETS && !wxUSE_SELECT_DISPATCHER +#if wxUSE_SOCKETS && !wxUSE_CONSOLE_EVENTLOOP # ifdef wxABORT_ON_CONFIG_ERROR # error "wxSocket requires wxSelectDispatcher in wxDFB" # else -# undef wxUSE_SELECT_DISPATCHER -# define wxUSE_SELECT_DISPATCHER 1 +# undef wxUSE_CONSOLE_EVENTLOOP +# define wxUSE_CONSOLE_EVENTLOOP 1 # endif #endif diff --git a/include/wx/dfb/evtloop.h b/include/wx/dfb/evtloop.h index 4c3380819a..9b010a1034 100644 --- a/include/wx/dfb/evtloop.h +++ b/include/wx/dfb/evtloop.h @@ -12,44 +12,35 @@ #define _WX_DFB_EVTLOOP_H_ #include "wx/dfb/dfbptr.h" +#include "wx/unix/evtloop.h" wxDFB_DECLARE_INTERFACE(IDirectFBEventBuffer); -struct wxDFBEvent; // ---------------------------------------------------------------------------- // wxEventLoop // ---------------------------------------------------------------------------- -class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxEventLoopManual +class WXDLLIMPEXP_CORE wxGUIEventLoop : public wxConsoleEventLoop { public: wxGUIEventLoop(); - virtual bool Pending() const; - virtual bool Dispatch(); - virtual int DispatchTimeout(unsigned long timeout); - // returns DirectFB event buffer used by wx static wxIDirectFBEventBufferPtr GetDirectFBEventBuffer(); +private: // wxYield implementation: iterate the loop as long as there are any // pending events void Yield(); -protected: - virtual void WakeUp(); - virtual void OnNextIteration(); - - virtual void HandleDFBEvent(const wxDFBEvent& event); - -private: static void InitBuffer(); static void CleanUp(); - friend class wxApp; // calls CleanUp() and WakeUp() + friend class wxApp; // calls CleanUp() private: static wxIDirectFBEventBufferPtr ms_buffer; + static int ms_bufferFd; DECLARE_NO_COPY_CLASS(wxGUIEventLoop) }; diff --git a/include/wx/dfb/nonownedwnd.h b/include/wx/dfb/nonownedwnd.h index 2363c785e6..86b7200aa1 100644 --- a/include/wx/dfb/nonownedwnd.h +++ b/include/wx/dfb/nonownedwnd.h @@ -18,6 +18,7 @@ wxDFB_DECLARE_INTERFACE(IDirectFBWindow); class wxDfbQueuedPaintRequests; struct wxDFBWindowEvent; +class wxDFBEventsHandler; //----------------------------------------------------------------------------- // wxNonOwnedWindow @@ -118,8 +119,8 @@ private: // are we currently painting some area of this TLW? bool m_isPainting; - friend class wxGUIEventLoop; // for HandleDFBWindowEvent - friend class wxWindowDFB; // for SetDfbFocus + friend class wxDFBEventsHandler; // for HandleDFBWindowEvent + friend class wxWindowDFB; // for SetDfbFocus }; #endif // _WX_DFB_NONOWNEDWND_H_ diff --git a/include/wx/dfb/wrapdfb.h b/include/wx/dfb/wrapdfb.h index da753b6063..602dd7c5fb 100644 --- a/include/wx/dfb/wrapdfb.h +++ b/include/wx/dfb/wrapdfb.h @@ -368,39 +368,9 @@ struct wxIDirectFBEventBuffer : public wxDfbWrapper { wxIDirectFBEventBuffer(IDirectFBEventBuffer *s) { Init(s); } - bool WakeUp() + bool CreateFileDescriptor(int *ret_fd) { - return Check(m_ptr->WakeUp(m_ptr)); - } - - bool HasEvent() - { - // returns DFB_OK if there is >=1 event, DFB_BUFFEREMPTY otherwise - DFBResult r = m_ptr->HasEvent(m_ptr); - - // NB: Check() also returns true for DFB_BUFFEREMPTY, so we can't just - // return it's return value: - Check(r); - return (r == DFB_OK); - } - - bool WaitForEventWithTimeout(unsigned secs, unsigned millisecs) - { - DFBResult r = m_ptr->WaitForEventWithTimeout(m_ptr, secs, millisecs); - - // DFB_TIMEOUT is not an error in this function: - if ( r == DFB_TIMEOUT ) - { - m_lastResult = DFB_TIMEOUT; - return true; - } - - return Check(r); - } - - bool GetEvent(wxDFBEvent& event) - { - return Check(m_ptr->GetEvent(m_ptr, &event)); + return Check(m_ptr->CreateFileDescriptor(m_ptr, ret_fd)); } }; diff --git a/include/wx/unix/private/timer.h b/include/wx/unix/private/timer.h index 2249fe5c2e..630676cb37 100644 --- a/include/wx/unix/private/timer.h +++ b/include/wx/unix/private/timer.h @@ -23,7 +23,9 @@ typedef wxMilliClock_t wxUsecClock_t; // wxTimer implementation class for Unix platforms // ---------------------------------------------------------------------------- -class wxUnixTimerImpl : public wxTimerImpl +// NB: we have to export at least this symbol from the shared library, because +// it's used by wxDFB's wxCore +class WXDLLIMPEXP_BASE wxUnixTimerImpl : public wxTimerImpl { public: wxUnixTimerImpl(wxTimer *timer); diff --git a/src/dfb/evtloop.cpp b/src/dfb/evtloop.cpp index 7f7807ac72..fd3f6b5818 100644 --- a/src/dfb/evtloop.cpp +++ b/src/dfb/evtloop.cpp @@ -26,10 +26,10 @@ #endif #include "wx/thread.h" -#include "wx/generic/private/timer.h" #include "wx/private/fdiodispatcher.h" #include "wx/dfb/private.h" #include "wx/nonownedwnd.h" +#include "wx/buffer.h" #define TRACE_EVENTS "events" @@ -37,14 +37,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 +156,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,85 +200,6 @@ 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() -{ - // 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 - // - // TODO: remove this hack, instead use CreateFileDescriptor() to properly - // multiplex GUI and socket input - const int TIMEOUT = 100; - - // treat time out (-1 return value) as normal successful return so that - // OnNextIteration() is called - return !!DispatchTimeout(TIMEOUT); -} - -int wxGUIEventLoop::DispatchTimeout(unsigned long timeout) -{ - wxCHECK_MSG( ms_buffer, 0, "invalid event buffer" ); - - // 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: - return -1; - - default: - // don't terminate the loop due to errors (they were reported - // already by ms_buffer) - break; - } - } - - return 1; -} - -void wxGUIEventLoop::WakeUp() -{ - wxCHECK_RET( ms_buffer, "invalid event buffer" ); - - ms_buffer->WakeUp(); -} - -void wxGUIEventLoop::OnNextIteration() -{ -#if wxUSE_TIMER - wxGenericTimerImpl::NotifyTimers(); -#endif - -#if wxUSE_SOCKETS - // handle any pending socket events: - wxFDIODispatcher::DispatchPending(); -#endif -} - void wxGUIEventLoop::Yield() { // process all pending events: @@ -162,33 +209,3 @@ void wxGUIEventLoop::Yield() // handle timers, sockets etc. OnNextIteration(); } - - -//----------------------------------------------------------------------------- -// DirectFB -> wxWidgets events translation -//----------------------------------------------------------------------------- - -void wxGUIEventLoop::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()); - } - } -} diff --git a/src/dfb/utils.cpp b/src/dfb/utils.cpp index df106bdad3..da9e2baa9d 100644 --- a/src/dfb/utils.cpp +++ b/src/dfb/utils.cpp @@ -19,6 +19,7 @@ #include "wx/evtloop.h" #include "wx/apptrait.h" #include "wx/unix/execute.h" +#include "wx/unix/private/timer.h" #ifndef WX_PRECOMP #include "wx/app.h" @@ -45,6 +46,11 @@ wxEventLoopBase* wxGUIAppTraits::CreateEventLoop() return new wxEventLoop; } +wxTimerImpl *wxGUIAppTraits::CreateTimerImpl(wxTimer *timer) +{ + return new wxUnixTimerImpl(timer); +} + // ---------------------------------------------------------------------------- // display characteristics // ---------------------------------------------------------------------------- -- 2.47.2