From 71e9885be0a84f3c544b992aeb3a842f821035b5 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 3 Jul 2013 00:28:42 +0000 Subject: [PATCH] Make wxEventLoop::AddSourceForFD() static. Any event sources should be registered with all the event loops, including the ones that will be started in the future, and not only the current (and potentially not even existing yet) one. So make AddSourceForFD() method static. To still allow it to do different things in console and GUI applications, as it must, virtualize it via the new wxEventLoopSourcesManager class which has different implementations in the two cases, returned via wxAppTraits as usual. Notice that this required moving the implementation of this method from src/osx/core/evtloop_cf.cpp to src/osx/core/utilsexc_cf.cpp as the former file is base-only and didn't have access to wxGUIAppTraits. See #10258. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74341 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/evtloop.h | 19 +--- include/wx/gtk/evtloop.h | 5 -- include/wx/osx/core/evtloop.h | 5 -- include/wx/osx/evtloopsrc.h | 2 +- include/wx/private/eventloopsourcesmanager.h | 26 ++++++ include/wx/unix/apptbase.h | 5 ++ include/wx/unix/apptrait.h | 2 + include/wx/unix/evtloop.h | 5 -- src/common/evtloopcmn.cpp | 25 ++++++ src/gtk/evtloop.cpp | 76 +++++++++------- src/osx/core/evtloop_cf.cpp | 74 ---------------- src/osx/core/utilsexc_cf.cpp | 92 ++++++++++++++++++++ src/unix/evtloopunix.cpp | 44 ++++++---- 13 files changed, 226 insertions(+), 154 deletions(-) create mode 100644 include/wx/private/eventloopsourcesmanager.h diff --git a/include/wx/evtloop.h b/include/wx/evtloop.h index 2abbd9cef4..a9034aeac8 100644 --- a/include/wx/evtloop.h +++ b/include/wx/evtloop.h @@ -79,9 +79,9 @@ public: #if wxUSE_EVENTLOOP_SOURCE // create a new event loop source wrapping the given file descriptor and - // start monitoring it - virtual wxEventLoopSource * - AddSourceForFD(int fd, wxEventLoopSourceHandler *handler, int flags) = 0; + // monitor it for events occurring on this descriptor in all event loops + static wxEventLoopSource * + AddSourceForFD(int fd, wxEventLoopSourceHandler *handler, int flags); #endif // wxUSE_EVENTLOOP_SOURCE // dispatch&processing @@ -296,19 +296,6 @@ public: wxGUIEventLoop() { m_impl = NULL; } virtual ~wxGUIEventLoop(); -#if wxUSE_EVENTLOOP_SOURCE - // We need to define a base class pure virtual method but we can't provide - // a generic implementation for it so simply fail. - virtual wxEventLoopSource * - AddSourceForFD(int WXUNUSED(fd), - wxEventLoopSourceHandler * WXUNUSED(handler), - int WXUNUSED(flags)) - { - wxFAIL_MSG( "support for event loop sources not implemented" ); - return NULL; - } -#endif // wxUSE_EVENTLOOP_SOURCE - virtual void ScheduleExit(int rc = 0); virtual bool Pending() const; virtual bool Dispatch(); diff --git a/include/wx/gtk/evtloop.h b/include/wx/gtk/evtloop.h index af4d00348d..9fb55aa226 100644 --- a/include/wx/gtk/evtloop.h +++ b/include/wx/gtk/evtloop.h @@ -29,11 +29,6 @@ public: virtual void WakeUp(); virtual bool YieldFor(long eventsToProcess); -#if wxUSE_EVENTLOOP_SOURCE - virtual wxEventLoopSource * - AddSourceForFD(int fd, wxEventLoopSourceHandler *handler, int flags); -#endif // wxUSE_EVENTLOOP_SOURCE - void StoreGdkEventForLaterProcessing(GdkEvent* ev) { m_arrGdkEvents.Add(ev); } diff --git a/include/wx/osx/core/evtloop.h b/include/wx/osx/core/evtloop.h index 862a4d9d54..5bc53b0c16 100644 --- a/include/wx/osx/core/evtloop.h +++ b/include/wx/osx/core/evtloop.h @@ -45,11 +45,6 @@ public: virtual bool YieldFor(long eventsToProcess); -#if wxUSE_EVENTLOOP_SOURCE - virtual wxEventLoopSource * - AddSourceForFD(int fd, wxEventLoopSourceHandler *handler, int flags); -#endif // wxUSE_EVENTLOOP_SOURCE - bool ShouldProcessIdleEvents() const { return m_processIdleEvents ; } #if wxUSE_UIACTIONSIMULATOR diff --git a/include/wx/osx/evtloopsrc.h b/include/wx/osx/evtloopsrc.h index 3c18bba764..646190eb72 100644 --- a/include/wx/osx/evtloopsrc.h +++ b/include/wx/osx/evtloopsrc.h @@ -17,7 +17,7 @@ typedef struct __CFFileDescriptor *CFFileDescriptorRef; // wxCFEventLoopSource: CoreFoundation-based wxEventLoopSource for OS X // ---------------------------------------------------------------------------- -class wxCFEventLoopSource : public wxEventLoopSource +class WXDLLIMPEXP_BASE wxCFEventLoopSource : public wxEventLoopSource { public: wxCFEventLoopSource(wxEventLoopSourceHandler *handler, int flags) diff --git a/include/wx/private/eventloopsourcesmanager.h b/include/wx/private/eventloopsourcesmanager.h new file mode 100644 index 0000000000..82aadf5243 --- /dev/null +++ b/include/wx/private/eventloopsourcesmanager.h @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/private/eventloopsourcesmanager.h +// Purpose: declares wxEventLoopSourcesManagerBase class +// Author: Rob Bresalier +// Created: 2013-06-19 +// RCS-ID: $Id$ +// Copyright: (c) 2013 Rob Bresalier +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_PRIVATE_EVENTLOOPSOURCESMANAGER_H_ +#define _WX_PRIVATE_EVENTLOOPSOURCESMANAGER_H_ + +// For pulling in the value of wxUSE_EVENTLOOP_SOURCE +#include "wx/evtloop.h" + +class WXDLLIMPEXP_BASE wxEventLoopSourcesManagerBase +{ +public: +#if wxUSE_EVENTLOOP_SOURCE + virtual wxEventLoopSource* + AddSourceForFD(int fd, wxEventLoopSourceHandler *handler, int flags) = 0; +#endif +}; + +#endif // _WX_PRIVATE_EVENTLOOPSOURCESMANAGER_H_ diff --git a/include/wx/unix/apptbase.h b/include/wx/unix/apptbase.h index 8bf6b4cb97..fd624aeed4 100644 --- a/include/wx/unix/apptbase.h +++ b/include/wx/unix/apptbase.h @@ -15,6 +15,7 @@ struct wxEndProcessData; struct wxExecuteData; class wxFDIOManager; +class wxEventLoopSourcesManagerBase; // ---------------------------------------------------------------------------- // wxAppTraits: the Unix version adds extra hooks needed by Unix code @@ -56,6 +57,10 @@ public: virtual wxFDIOManager *GetFDIOManager(); #endif // wxUSE_SOCKETS + // Return a non-NULL pointer to the object responsible for managing the + // event loop sources in this kind of application. + virtual wxEventLoopSourcesManagerBase* GetEventLoopSourcesManager(); + protected: // a helper for the implementation of WaitForChild() in wxGUIAppTraits: // checks the streams used for redirected IO in execData and returns true diff --git a/include/wx/unix/apptrait.h b/include/wx/unix/apptrait.h index 04109204e9..5f56733d28 100644 --- a/include/wx/unix/apptrait.h +++ b/include/wx/unix/apptrait.h @@ -88,6 +88,8 @@ public: #endif #endif // wxUSE_SOCKETS + + virtual wxEventLoopSourcesManagerBase* GetEventLoopSourcesManager(); }; #endif // wxUSE_GUI diff --git a/include/wx/unix/evtloop.h b/include/wx/unix/evtloop.h index 5f1cf59ea1..0b71766068 100644 --- a/include/wx/unix/evtloop.h +++ b/include/wx/unix/evtloop.h @@ -41,11 +41,6 @@ public: virtual bool IsOk() const { return m_dispatcher != NULL; } virtual bool YieldFor(long WXUNUSED(eventsToProcess)) { return true; } -#if wxUSE_EVENTLOOP_SOURCE - virtual wxEventLoopSource * - AddSourceForFD(int fd, wxEventLoopSourceHandler *handler, int flags); -#endif // wxUSE_EVENTLOOP_SOURCE - protected: virtual void OnNextIteration(); diff --git a/src/common/evtloopcmn.cpp b/src/common/evtloopcmn.cpp index da0b79fba4..8564f52517 100644 --- a/src/common/evtloopcmn.cpp +++ b/src/common/evtloopcmn.cpp @@ -23,6 +23,8 @@ #endif //WX_PRECOMP #include "wx/scopeguard.h" +#include "wx/apptrait.h" +#include "wx/private/eventloopsourcesmanager.h" // ---------------------------------------------------------------------------- // wxEventLoopBase @@ -115,6 +117,29 @@ bool wxEventLoopBase::Yield(bool onlyIfNeeded) return YieldFor(wxEVT_CATEGORY_ALL); } +#if wxUSE_EVENTLOOP_SOURCE + +wxEventLoopSource* +wxEventLoopBase::AddSourceForFD(int fd, + wxEventLoopSourceHandler *handler, + int flags) +{ + // Ensure that we have some valid traits. + wxConsoleAppTraits traitsConsole; + wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + if ( !traits ) + traits = &traitsConsole; + + // And delegate to the event loop sources manager defined by it. + wxEventLoopSourcesManagerBase* const + manager = traits->GetEventLoopSourcesManager(); + wxCHECK_MSG( manager, NULL, wxS("Must have wxEventLoopSourcesManager") ); + + return manager->AddSourceForFD(fd, handler, flags); +} + +#endif // wxUSE_EVENTLOOP_SOURCE + // wxEventLoopManual is unused in the other ports #if defined(__WINDOWS__) || defined(__WXDFB__) || ( ( defined(__UNIX__) && !defined(__WXOSX__) ) && wxUSE_BASE) diff --git a/src/gtk/evtloop.cpp b/src/gtk/evtloop.cpp index d104d82f0c..ea5b43b9d1 100644 --- a/src/gtk/evtloop.cpp +++ b/src/gtk/evtloop.cpp @@ -32,6 +32,9 @@ #include "wx/log.h" #endif // WX_PRECOMP +#include "wx/private/eventloopsourcesmanager.h" +#include "wx/apptrait.h" + #include #include @@ -133,41 +136,50 @@ static gboolean wx_on_channel_event(GIOChannel *channel, } } -wxEventLoopSource * -wxGUIEventLoop::AddSourceForFD(int fd, - wxEventLoopSourceHandler *handler, - int flags) +class wxGUIEventLoopSourcesManager : public wxEventLoopSourcesManagerBase { - wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" ); - - int condition = 0; - if (flags & wxEVENT_SOURCE_INPUT) - condition |= G_IO_IN | G_IO_PRI; - if (flags & wxEVENT_SOURCE_OUTPUT) - condition |= G_IO_OUT; - if (flags & wxEVENT_SOURCE_EXCEPTION) - condition |= G_IO_ERR | G_IO_HUP | G_IO_NVAL; - - GIOChannel* channel = g_io_channel_unix_new(fd); - const unsigned sourceId = g_io_add_watch - ( - channel, - (GIOCondition)condition, - &wx_on_channel_event, - handler - ); - // it was ref'd by g_io_add_watch() so we can unref it here - g_io_channel_unref(channel); - - if ( !sourceId ) - return NULL; - - wxLogTrace(wxTRACE_EVT_SOURCE, - "Adding event loop source for fd=%d with GTK id=%u", - fd, sourceId); +public: + virtual wxEventLoopSource* + AddSourceForFD(int fd, wxEventLoopSourceHandler *handler, int flags) + { + wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" ); + + int condition = 0; + if ( flags & wxEVENT_SOURCE_INPUT ) + condition |= G_IO_IN | G_IO_PRI | G_IO_HUP; + if ( flags & wxEVENT_SOURCE_OUTPUT ) + condition |= G_IO_OUT; + if ( flags & wxEVENT_SOURCE_EXCEPTION ) + condition |= G_IO_ERR | G_IO_NVAL; + + GIOChannel* channel = g_io_channel_unix_new(fd); + const unsigned sourceId = g_io_add_watch + ( + channel, + (GIOCondition)condition, + &wx_on_channel_event, + handler + ); + // it was ref'd by g_io_add_watch() so we can unref it here + g_io_channel_unref(channel); + + if ( !sourceId ) + return NULL; + + wxLogTrace(wxTRACE_EVT_SOURCE, + "Adding event loop source for fd=%d with GTK id=%u", + fd, sourceId); + + + return new wxGTKEventLoopSource(sourceId, handler, flags); + } +}; +wxEventLoopSourcesManagerBase* wxGUIAppTraits::GetEventLoopSourcesManager() +{ + static wxGUIEventLoopSourcesManager s_eventLoopSourcesManager; - return new wxGTKEventLoopSource(sourceId, handler, flags); + return &s_eventLoopSourcesManager; } wxGTKEventLoopSource::~wxGTKEventLoopSource() diff --git a/src/osx/core/evtloop_cf.cpp b/src/osx/core/evtloop_cf.cpp index 12ecb2c872..704a833413 100644 --- a/src/osx/core/evtloop_cf.cpp +++ b/src/osx/core/evtloop_cf.cpp @@ -48,80 +48,6 @@ #if wxUSE_EVENTLOOP_SOURCE -namespace -{ - -void EnableDescriptorCallBacks(CFFileDescriptorRef cffd, int flags) -{ - if ( flags & wxEVENT_SOURCE_INPUT ) - CFFileDescriptorEnableCallBacks(cffd, kCFFileDescriptorReadCallBack); - if ( flags & wxEVENT_SOURCE_OUTPUT ) - CFFileDescriptorEnableCallBacks(cffd, kCFFileDescriptorWriteCallBack); -} - -void -wx_cffiledescriptor_callback(CFFileDescriptorRef cffd, - CFOptionFlags flags, - void *ctxData) -{ - wxLogTrace(wxTRACE_EVT_SOURCE, - "CFFileDescriptor callback, flags=%d", flags); - - wxCFEventLoopSource * const - source = static_cast(ctxData); - - wxEventLoopSourceHandler * const - handler = source->GetHandler(); - if ( flags & kCFFileDescriptorReadCallBack ) - handler->OnReadWaiting(); - if ( flags & kCFFileDescriptorWriteCallBack ) - handler->OnWriteWaiting(); - - // we need to re-enable callbacks to be called again - EnableDescriptorCallBacks(cffd, source->GetFlags()); -} - -} // anonymous namespace - -wxEventLoopSource * -wxCFEventLoop::AddSourceForFD(int fd, - wxEventLoopSourceHandler *handler, - int flags) -{ - wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" ); - - wxScopedPtr - source(new wxCFEventLoopSource(handler, flags)); - - CFFileDescriptorContext ctx = { 0, source.get(), NULL, NULL, NULL }; - wxCFRef - cffd(CFFileDescriptorCreate - ( - kCFAllocatorDefault, - fd, - true, // close on invalidate - wx_cffiledescriptor_callback, - &ctx - )); - if ( !cffd ) - return NULL; - - wxCFRef - cfsrc(CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, cffd, 0)); - if ( !cfsrc ) - return NULL; - - CFRunLoopRef cfloop = CFGetCurrentRunLoop(); - CFRunLoopAddSource(cfloop, cfsrc, kCFRunLoopDefaultMode); - - // Enable the callbacks initially. - EnableDescriptorCallBacks(cffd, source->GetFlags()); - - source->SetFileDescriptor(cffd.release()); - - return source.release(); -} - void wxCFEventLoopSource::SetFileDescriptor(CFFileDescriptorRef cffd) { wxASSERT_MSG( !m_cffd, "shouldn't be called more than once" ); diff --git a/src/osx/core/utilsexc_cf.cpp b/src/osx/core/utilsexc_cf.cpp index fe010f63be..221bbb322d 100644 --- a/src/osx/core/utilsexc_cf.cpp +++ b/src/osx/core/utilsexc_cf.cpp @@ -22,8 +22,13 @@ #include "wx/thread.h" #include "wx/process.h" +#include "wx/evtloop.h" +#include "wx/evtloopsrc.h" +#include "wx/private/eventloopsourcesmanager.h" + #include +#include #include /*! @@ -104,6 +109,93 @@ int wxGUIAppTraits::AddProcessCallback(wxEndProcessData *proc_data, int fd) return ++s_last_tag; } +#if wxUSE_EVENTLOOP_SOURCE + +namespace +{ + +void EnableDescriptorCallBacks(CFFileDescriptorRef cffd, int flags) +{ + if ( flags & wxEVENT_SOURCE_INPUT ) + CFFileDescriptorEnableCallBacks(cffd, kCFFileDescriptorReadCallBack); + if ( flags & wxEVENT_SOURCE_OUTPUT ) + CFFileDescriptorEnableCallBacks(cffd, kCFFileDescriptorWriteCallBack); +} + +void +wx_cffiledescriptor_callback(CFFileDescriptorRef cffd, + CFOptionFlags flags, + void *ctxData) +{ + wxLogTrace(wxTRACE_EVT_SOURCE, + "CFFileDescriptor callback, flags=%d", flags); + + wxCFEventLoopSource * const + source = static_cast(ctxData); + + wxEventLoopSourceHandler * const + handler = source->GetHandler(); + if ( flags & kCFFileDescriptorReadCallBack ) + handler->OnReadWaiting(); + if ( flags & kCFFileDescriptorWriteCallBack ) + handler->OnWriteWaiting(); + + // we need to re-enable callbacks to be called again + EnableDescriptorCallBacks(cffd, source->GetFlags()); +} + +} // anonymous namespace + +class wxCFEventLoopSourcesManager : public wxEventLoopSourcesManagerBase +{ +public: + wxEventLoopSource * + AddSourceForFD(int fd, wxEventLoopSourceHandler *handler, int flags) + { + wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" ); + + wxScopedPtr + source(new wxCFEventLoopSource(handler, flags)); + + CFFileDescriptorContext ctx = { 0, source.get(), NULL, NULL, NULL }; + wxCFRef + cffd(CFFileDescriptorCreate + ( + kCFAllocatorDefault, + fd, + true, // close on invalidate + wx_cffiledescriptor_callback, + &ctx + )); + if ( !cffd ) + return NULL; + + wxCFRef + cfsrc(CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, cffd, 0)); + if ( !cfsrc ) + return NULL; + + CFRunLoopRef cfloop = CFRunLoopGetCurrent(); + CFRunLoopAddSource(cfloop, cfsrc, kCFRunLoopDefaultMode); + + // Enable the callbacks initially. + EnableDescriptorCallBacks(cffd, source->GetFlags()); + + source->SetFileDescriptor(cffd.release()); + + return source.release(); + } +}; + +wxEventLoopSourcesManagerBase* wxGUIAppTraits::GetEventLoopSourcesManager() +{ + static wxCFEventLoopSourcesManager s_eventLoopSourcesManager; + + return &s_eventLoopSourcesManager; +} + +#endif // wxUSE_EVENTLOOP_SOURCE + ///////////////////////////////////////////////////////////////////////////// // NOTE: This doesn't really belong here but this was a handy file to diff --git a/src/unix/evtloopunix.cpp b/src/unix/evtloopunix.cpp index 784241c663..763b73ef73 100644 --- a/src/unix/evtloopunix.cpp +++ b/src/unix/evtloopunix.cpp @@ -36,7 +36,9 @@ #include "wx/unix/private/epolldispatcher.h" #include "wx/unix/private/wakeuppipe.h" #include "wx/private/selectdispatcher.h" +#include "wx/private/eventloopsourcesmanager.h" #include "wx/private/fdioeventloopsourcehandler.h" +#include "wx/private/eventloopsourcesmanager.h" #if wxUSE_EVENTLOOP_SOURCE #include "wx/evtloopsrc.h" @@ -87,27 +89,37 @@ wxConsoleEventLoop::~wxConsoleEventLoop() #if wxUSE_EVENTLOOP_SOURCE -wxEventLoopSource * -wxConsoleEventLoop::AddSourceForFD(int fd, - wxEventLoopSourceHandler *handler, - int flags) +class wxConsoleEventLoopSourcesManager : public wxEventLoopSourcesManagerBase { - wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" ); +public: + wxEventLoopSource* AddSourceForFD( int fd, + wxEventLoopSourceHandler *handler, + int flags) + { + wxCHECK_MSG( fd != -1, NULL, "can't monitor invalid fd" ); - wxLogTrace(wxTRACE_EVT_SOURCE, - "Adding event loop source for fd=%d", fd); + wxLogTrace(wxTRACE_EVT_SOURCE, + "Adding event loop source for fd=%d", fd); + + // we need a bridge to wxFDIODispatcher + // + // TODO: refactor the code so that only wxEventLoopSourceHandler is used + wxScopedPtr + fdioHandler(new wxFDIOEventLoopSourceHandler(handler)); - // we need a bridge to wxFDIODispatcher - // - // TODO: refactor the code so that only wxEventLoopSourceHandler is used - wxScopedPtr - fdioHandler(new wxFDIOEventLoopSourceHandler(handler)); + if ( !wxFDIODispatcher::Get()->RegisterFD(fd, fdioHandler.get(), flags) ) + return NULL; - if ( !m_dispatcher->RegisterFD(fd, fdioHandler.get(), flags) ) - return NULL; + return new wxUnixEventLoopSource(wxFDIODispatcher::Get(), fdioHandler.release(), + fd, handler, flags); + } +}; + +wxEventLoopSourcesManagerBase* wxAppTraits::GetEventLoopSourcesManager() +{ + static wxConsoleEventLoopSourcesManager s_eventLoopSourcesManager; - return new wxUnixEventLoopSource(m_dispatcher, fdioHandler.release(), - fd, handler, flags); + return &s_eventLoopSourcesManager; } wxUnixEventLoopSource::~wxUnixEventLoopSource() -- 2.45.2