From: Vadim Zeitlin Date: Tue, 22 Nov 2011 13:18:50 +0000 (+0000) Subject: Add wxEventFilter and related functionality. X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/58cc15871d1a5ec5a6cc17f50be3e2006f57571f Add wxEventFilter and related functionality. Allow defining event filters to globally pre-process all application events without having to override wxApp::FilterEvent(). git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@69794 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/Makefile.in b/Makefile.in index 26178b823c..1f8ae16ef1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -359,6 +359,7 @@ ALL_BASE_HEADERS = \ wx/dynload.h \ wx/encconv.h \ wx/event.h \ + wx/eventfilter.h \ wx/evtloop.h \ wx/except.h \ wx/features.h \ @@ -537,6 +538,7 @@ ALL_PORTS_BASE_HEADERS = \ wx/dynload.h \ wx/encconv.h \ wx/event.h \ + wx/eventfilter.h \ wx/evtloop.h \ wx/except.h \ wx/features.h \ diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index 54ebc7d67f..077566a221 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -447,6 +447,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! wx/dynload.h wx/encconv.h wx/event.h + wx/eventfilter.h wx/evtloop.h wx/except.h wx/features.h diff --git a/build/msw/wx_base.dsp b/build/msw/wx_base.dsp index b2c5cecd85..88e1fd1665 100644 --- a/build/msw/wx_base.dsp +++ b/build/msw/wx_base.dsp @@ -1231,6 +1231,10 @@ SOURCE=..\..\include\wx\event.h # End Source File # Begin Source File +SOURCE=..\..\include\wx\eventfilter.h +# End Source File +# Begin Source File + SOURCE=..\..\include\wx\evtloop.h # End Source File # Begin Source File diff --git a/build/msw/wx_vc7_base.vcproj b/build/msw/wx_vc7_base.vcproj index 5cc48f7057..cf6c2e6d2a 100644 --- a/build/msw/wx_vc7_base.vcproj +++ b/build/msw/wx_vc7_base.vcproj @@ -1348,6 +1348,9 @@ RelativePath="..\..\include\wx\event.h"> + + + + diff --git a/build/msw/wx_vc9_base.vcproj b/build/msw/wx_vc9_base.vcproj index fa87ab04ba..dd7944e16e 100644 --- a/build/msw/wx_vc9_base.vcproj +++ b/build/msw/wx_vc9_base.vcproj @@ -1814,6 +1814,10 @@ > + + diff --git a/docs/changes.txt b/docs/changes.txt index 71959ce5f5..7cb9c4efb5 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -457,6 +457,7 @@ All: - Fix parsing of negated long options in wxCmdLineParser (roed_bis). - Fix crash in wxArray::insert() overload taking iterator range (wsu). +- Added wxEventFilter class and wxEvtHandler::{Add,Remove}Filter(). All (GUI): diff --git a/include/wx/app.h b/include/wx/app.h index 0ea4a57464..271c4b1207 100644 --- a/include/wx/app.h +++ b/include/wx/app.h @@ -18,6 +18,7 @@ // ---------------------------------------------------------------------------- #include "wx/event.h" // for the base class +#include "wx/eventfilter.h" // (and another one) #include "wx/build.h" #include "wx/cmdargs.h" // for wxCmdLineArgsArray used by wxApp::argv #include "wx/init.h" // we must declare wxEntry() @@ -70,7 +71,8 @@ extern WXDLLIMPEXP_DATA_BASE(wxList) wxPendingDelete; // wxAppConsoleBase: wxApp for non-GUI applications // ---------------------------------------------------------------------------- -class WXDLLIMPEXP_BASE wxAppConsoleBase : public wxEvtHandler +class WXDLLIMPEXP_BASE wxAppConsoleBase : public wxEvtHandler, + public wxEventFilter { public: // ctor and dtor @@ -238,13 +240,8 @@ public: // event processing functions // -------------------------- - // this method allows to filter all the events processed by the program, so - // you should try to return quickly from it to avoid slowing down the - // program to the crawl - // - // return value should be -1 to continue with the normal event processing, - // or TRUE or FALSE to stop further processing and pretend that the event - // had been already processed or won't be processed at all, respectively + // Implement the inherited wxEventFilter method but just return -1 from it + // to indicate that default processing should take place. virtual int FilterEvent(wxEvent& event); // return true if we're running event loop, i.e. if the events can diff --git a/include/wx/event.h b/include/wx/event.h index a94c5375df..70ea52e26e 100644 --- a/include/wx/event.h +++ b/include/wx/event.h @@ -39,6 +39,7 @@ class WXDLLIMPEXP_FWD_BASE wxList; class WXDLLIMPEXP_FWD_BASE wxEvent; +class WXDLLIMPEXP_FWD_BASE wxEventFilter; #if wxUSE_GUI class WXDLLIMPEXP_FWD_CORE wxDC; class WXDLLIMPEXP_FWD_CORE wxMenu; @@ -3013,6 +3014,19 @@ public: bool IsUnlinked() const; + // Global event filters + // -------------------- + + // Add an event filter whose FilterEvent() method will be called for each + // and every event processed by wxWidgets. The filters are called in LIFO + // order and wxApp is registered as an event filter by default. The pointer + // must remain valid until it's removed with RemoveFilter() and is not + // deleted by wxEvtHandler. + static void AddFilter(wxEventFilter* filter); + + // Remove a filter previously installed with AddFilter(). + static void RemoveFilter(wxEventFilter* filter); + // Event queuing and processing // ---------------------------- @@ -3360,6 +3374,9 @@ private: // try to process events in all handlers chained to this one bool DoTryChain(wxEvent& event); + // Head of the event filter linked list. + static wxEventFilter* ms_filterList; + DECLARE_DYNAMIC_CLASS_NO_COPY(wxEvtHandler) }; diff --git a/include/wx/eventfilter.h b/include/wx/eventfilter.h new file mode 100644 index 0000000000..0aec4a3f8f --- /dev/null +++ b/include/wx/eventfilter.h @@ -0,0 +1,72 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/eventfilter.h +// Purpose: wxEventFilter class declaration. +// Author: Vadim Zeitlin +// Created: 2011-11-21 +// RCS-ID: $Id: wxhead.h,v 1.12 2010-04-22 12:44:51 zeitlin Exp $ +// Copyright: (c) 2011 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_EVENTFILTER_H_ +#define _WX_EVENTFILTER_H_ + +#include "wx/defs.h" + +class WXDLLIMPEXP_FWD_BASE wxEvent; +class WXDLLIMPEXP_FWD_BASE wxEvtHandler; + +// ---------------------------------------------------------------------------- +// wxEventFilter is used with wxEvtHandler::AddFilter() and ProcessEvent(). +// ---------------------------------------------------------------------------- + +class wxEventFilter +{ +public: + // Possible return values for FilterEvent(). + // + // Notice that the values of these enum elements are fixed due to backwards + // compatibility constraints. + enum + { + // Process event as usual. + Event_Skip = -1, + + // Don't process the event normally at all. + Event_Ignore = 0, + + // Event was already handled, don't process it normally. + Event_Processed = 1 + }; + + wxEventFilter() + { + m_next = NULL; + } + + virtual ~wxEventFilter() + { + wxASSERT_MSG( !m_next, "Forgot to call wxEvtHandler::RemoveFilter()?" ); + } + + // This method allows to filter all the events processed by the program, so + // you should try to return quickly from it to avoid slowing down the + // program to the crawl. + // + // Return value should be -1 to continue with the normal event processing, + // or true or false to stop further processing and pretend that the event + // had been already processed or won't be processed at all, respectively. + virtual int FilterEvent(wxEvent& event) = 0; + +private: + // Objects of this class are made to be stored in a linked list in + // wxEvtHandler so put the next node ponter directly in the class itself. + wxEventFilter* m_next; + + // And provide access to it for wxEvtHandler [only]. + friend class wxEvtHandler; + + wxDECLARE_NO_COPY_CLASS(wxEventFilter); +}; + +#endif // _WX_EVENTFILTER_H_ diff --git a/interface/wx/app.h b/interface/wx/app.h index c17ad1c002..82bffae0a3 100644 --- a/interface/wx/app.h +++ b/interface/wx/app.h @@ -37,7 +37,8 @@ @see @ref overview_app, wxApp, wxAppTraits, wxEventLoopBase */ -class wxAppConsole : public wxEvtHandler +class wxAppConsole : public wxEvtHandler, + public wxEventFilter { protected: /** @@ -81,13 +82,14 @@ public: virtual void ExitMainLoop(); /** + Overridden wxEventFilter method. + This function is called before processing any event and allows the application - to preempt the processing of some events. + to preempt the processing of some events, see wxEventFilter + documentation for more information. - If this method returns -1 the event is processed normally, otherwise either - @true or @false should be returned and the event processing stops immediately - considering that the event had been already processed (for the former return - value) or that it is not going to be processed at all (for the latter one). + wxApp implementation of this method always return -1 indicating that + the event should be processed normally. */ virtual int FilterEvent(wxEvent& event); diff --git a/interface/wx/event.h b/interface/wx/event.h index 6262b8f363..e61807c55d 100644 --- a/interface/wx/event.h +++ b/interface/wx/event.h @@ -1088,6 +1088,40 @@ public: //@} + /** + @name Global event filters. + + Methods for working with the global list of event filters. + + Event filters can be defined to pre-process all the events that happen + in an application, see wxEventFilter documentation for more information. + */ + //@{ + + /** + Add an event filter whose FilterEvent() method will be called for each + and every event processed by wxWidgets. + + The filters are called in LIFO order and wxApp is registered as an + event filter by default. The pointer must remain valid until it's + removed with RemoveFilter() and is not deleted by wxEvtHandler. + + @since 2.9.3 + */ + static void AddFilter(wxEventFilter* filter); + + /** + Remove a filter previously installed with AddFilter(). + + It's an error to remove a filter that hadn't been previously added or + was already removed. + + @since 2.9.3 + */ + static void RemoveFilter(wxEventFilter* filter); + + //@} + protected: /** Method called by ProcessEvent() before examining this object event diff --git a/interface/wx/eventfilter.h b/interface/wx/eventfilter.h new file mode 100644 index 0000000000..4138f1fbb3 --- /dev/null +++ b/interface/wx/eventfilter.h @@ -0,0 +1,139 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: interface/wx/eventfilter.h +// Purpose: wxEventFilter class documentation +// Author: Vadim Zeitlin +// Created: 2011-11-21 +// RCS-ID: $Id$ +// Copyright: (c) 2011 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +/** + A global event filter for pre-processing all the events generated in the + program. + + This is a very simple class which just provides FilterEvent() virtual + method to be called by wxEvtHandler before starting process of any event. + Thus, inheriting from this class and overriding FilterEvent() allows to + capture and possibly handle or ignore all the events happening in the + program. Of course, having event filters adds additional overhead to every + event processing and so should not be used lightly and your FilterEvent() + code should try to return as quickly as possible, especially for the events + it is not interested in. + + An example of using this class: + @code + // This class allows to determine the last time the user has worked with + // this application: + class LastActivityTimeDetector : public wxEventFilter + { + public: + LastActivityTimeDetector() + { + wxEvtHandler::AddFilter(this); + + m_last = wxDateTime::Now(); + } + + virtual ~LastActivityTimeDetector() + { + wxEvtHandler::RemoveFilter(this); + } + + virtual int FilterEvent(wxEvent& event) + { + // Update the last user activity + const wxEventType t = event.GetEventType(); + if ( t == wxEVT_KEY_DOWN || t == wxEVT_MOTION || + t == wxEVT_LEFT_DOWN || + t == wxEVT_RIGHT_DOWN || + t == wxEVT_MIDDLE_DOWN ) + { + m_last = wxDateTime::Now(); + } + + // Continue processing the event normally as well. + return Event_Skip; + } + + // This function could be called periodically from some timer to + // do something (e.g. hide sensitive data or log out from remote + // server) if the user has been inactive for some time period. + bool IsInactiveFor(const wxTimeSpan& diff) const + { + return wxDateTime::Now() - diff > m_last; + } + + private: + wxDateTime m_last; + }; + @endcode + + Notice that wxApp derives from wxEventFilter and is registered as an event + filter during its creation so you may also override FilterEvent() method in + your wxApp-derived class and, in fact, this is often the most convenient + way to do it. However creating a new class deriving directly from + wxEventFilter allows to isolate the event filtering code in its own + separate class and also to have several independent filters, if necessary. + + @category{events} + + @since 2.9.3 + */ +class wxEventFilter +{ +public: + /// Possible return values for FilterEvent(). + enum + { + /// Process event as usual. + Event_Skip = -1, + + /// Don't process the event normally at all. + Event_Ignore = 0, + + /// Event was already handled, don't process it normally. + Event_Processed = 1 + }; + + /** + Default constructor. + + Constructor does not register this filter using + wxEvtHandler::AddFilter(), it's your responsibility to do it when + necessary. + + Notice that the objects of this class can't be copied. + */ + wxEventFilter(); + + /** + Destructor. + + You must call wxEvtHandler::RemoveFilter() before destroying this + object (possibly from the derived class destructor), failure to do this + is indicated by an assert unless assertions are disabled. + */ + virtual ~wxEventFilter(); + + /** + Override this method to implement event pre-processing. + + This method allows to filter all the events processed by the program, + so you should try to return quickly from it to avoid slowing down the + program to the crawl. + + Although the return type of this method is @c int, this is only due to + backwards compatibility concerns and the actual return value must be + one of the @c Event_XXX constants defined above: + - Event_Skip to continue processing the event normally (this should + be used in most cases). + - Event_Ignore to not process this event at all (this can be used + to suppress some events). + - Event_Processed to not process this event normally but indicate + that it was already processed by the event filter and so no default + processing should take place neither (this should only be used if + the filter really did process the event). + */ + virtual int FilterEvent(wxEvent& event) = 0; +}; diff --git a/src/common/appbase.cpp b/src/common/appbase.cpp index 194d0793ac..9ac78f57f6 100644 --- a/src/common/appbase.cpp +++ b/src/common/appbase.cpp @@ -150,10 +150,14 @@ wxAppConsoleBase::wxAppConsoleBase() wxDELETE(m_traits); #endif #endif + + wxEvtHandler::AddFilter(this); } wxAppConsoleBase::~wxAppConsoleBase() { + wxEvtHandler::RemoveFilter(this); + // we're being destroyed and using this object from now on may not work or // even crash so don't leave dangling pointers to it ms_appInstance = NULL; @@ -401,7 +405,7 @@ bool wxAppConsoleBase::IsMainLoopRunning() int wxAppConsoleBase::FilterEvent(wxEvent& WXUNUSED(event)) { // process the events normally by default - return -1; + return Event_Skip; } void wxAppConsoleBase::DelayPendingEventHandler(wxEvtHandler* toDelay) diff --git a/src/common/event.cpp b/src/common/event.cpp index 31e6e6adef..18e2386db0 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -25,6 +25,7 @@ #endif #include "wx/event.h" +#include "wx/eventfilter.h" #include "wx/evtloop.h" #ifndef WX_PRECOMP @@ -1132,6 +1133,43 @@ bool wxEvtHandler::IsUnlinked() const m_nextHandler == NULL; } +wxEventFilter* wxEvtHandler::ms_filterList = NULL; + +/* static */ void wxEvtHandler::AddFilter(wxEventFilter* filter) +{ + wxCHECK_RET( filter, "NULL filter" ); + + filter->m_next = ms_filterList; + ms_filterList = filter; +} + +/* static */ void wxEvtHandler::RemoveFilter(wxEventFilter* filter) +{ + wxEventFilter* prev = NULL; + for ( wxEventFilter* f = ms_filterList; f; f = f->m_next ) + { + if ( f == filter ) + { + // Set the previous list element or the list head to the next + // element. + if ( prev ) + prev->m_next = f->m_next; + else + ms_filterList = f->m_next; + + // Also reset the next pointer in the filter itself just to avoid + // having possibly dangling pointers, even though it's not strictly + // necessary. + f->m_next = NULL; + + // Skip the assert below. + return; + } + } + + wxFAIL_MSG( "Filter not found" ); +} + #if wxUSE_THREADS bool wxEvtHandler::ProcessThreadEvent(const wxEvent& event) @@ -1360,23 +1398,24 @@ bool wxEvtHandler::TryAfter(wxEvent& event) bool wxEvtHandler::ProcessEvent(wxEvent& event) { - // The very first thing we do is to allow the application to hook into - // event processing in order to globally pre-process all events. + // The very first thing we do is to allow any registered filters to hook + // into event processing in order to globally pre-process all events. // // Note that we should only do it if we're the first event handler called // to avoid calling FilterEvent() multiple times as the event goes through // the event handler chain and possibly upwards the window hierarchy. if ( !event.WasProcessed() ) { - if ( wxTheApp ) + for ( wxEventFilter* f = ms_filterList; f; f = f->m_next ) { - int rc = wxTheApp->FilterEvent(event); - if ( rc != -1 ) + int rc = f->FilterEvent(event); + if ( rc != wxEventFilter::Event_Skip ) { - wxASSERT_MSG( rc == 1 || rc == 0, - "unexpected wxApp::FilterEvent return value" ); + wxASSERT_MSG( rc == wxEventFilter::Event_Ignore || + rc == wxEventFilter::Event_Processed, + "unexpected FilterEvent() return value" ); - return rc != 0; + return rc != wxEventFilter::Event_Ignore; } //else: proceed normally } diff --git a/wxGTK.spec b/wxGTK.spec index 3dad0b791f..cd310242db 100644 --- a/wxGTK.spec +++ b/wxGTK.spec @@ -226,6 +226,7 @@ wx/dynlib.h wx/dynload.h wx/encconv.h wx/event.h +wx/eventfilter.h wx/evtloop.h wx/except.h wx/features.h diff --git a/wxMotif.spec b/wxMotif.spec index c6a2a80ec7..656e960308 100644 --- a/wxMotif.spec +++ b/wxMotif.spec @@ -128,6 +128,7 @@ wx/dynlib.h wx/dynload.h wx/encconv.h wx/event.h +wx/eventfilter.h wx/evtloop.h wx/except.h wx/features.h diff --git a/wxX11.spec b/wxX11.spec index 8d183a8691..8d0d4d5f28 100644 --- a/wxX11.spec +++ b/wxX11.spec @@ -152,6 +152,7 @@ wx/dynlib.h wx/dynload.h wx/encconv.h wx/event.h +wx/eventfilter.h wx/evtloop.h wx/except.h wx/features.h