Add wxEventFilter and related functionality.
authorVadim Zeitlin <vadim@wxwidgets.org>
Tue, 22 Nov 2011 13:18:50 +0000 (13:18 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Tue, 22 Nov 2011 13:18:50 +0000 (13:18 +0000)
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

18 files changed:
Makefile.in
build/bakefiles/files.bkl
build/msw/wx_base.dsp
build/msw/wx_vc7_base.vcproj
build/msw/wx_vc8_base.vcproj
build/msw/wx_vc9_base.vcproj
docs/changes.txt
include/wx/app.h
include/wx/event.h
include/wx/eventfilter.h [new file with mode: 0644]
interface/wx/app.h
interface/wx/event.h
interface/wx/eventfilter.h [new file with mode: 0644]
src/common/appbase.cpp
src/common/event.cpp
wxGTK.spec
wxMotif.spec
wxX11.spec

index 26178b823cf8b60beb72defca0b644ffc9efc27a..1f8ae16ef1087cde253e3ff9666785b94585af30 100644 (file)
@@ -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 \
index 54ebc7d67fd06538f81177e2f3a465d40fd11503..077566a2212b6989b275448c21f7bfcd31751e3f 100644 (file)
@@ -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
index b2c5cecd85c93a3efc25b98b900f875b91eed545..88e1fd1665e8e76a977568287f27a8569a9f4ff6 100644 (file)
@@ -1231,6 +1231,10 @@ SOURCE=..\..\include\wx\event.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=..\..\include\wx\eventfilter.h
+# End Source File
+# Begin Source File
+
 SOURCE=..\..\include\wx\evtloop.h\r
 # End Source File\r
 # Begin Source File\r
index 5cc48f70576b6ce495c9559139b24f5e2761e502..cf6c2e6d2ae2fe487f2fa1fa69d57a4e0833994d 100644 (file)
                                RelativePath="..\..\include\wx\event.h">\r
                        </File>\r
                        <File\r
+                               RelativePath="..\..\include\wx\eventfilter.h">
+                       </File>
+                       <File
                                RelativePath="..\..\include\wx\evtloop.h">\r
                        </File>\r
                        <File\r
index 1c380441416add6f370bc3aad312ec61c7a49e95..daae54782ed5fb394b3f06f3496405b8d3a5ee1e 100644 (file)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath="..\..\include\wx\eventfilter.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\include\wx\evtloop.h"\r
                                >\r
                        </File>\r
index fa87ab04bac150a93d34b6c4ae432144e9969727..dd7944e16e83a5be3826f6d1048ad04a45dcd82a 100644 (file)
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath="..\..\include\wx\eventfilter.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\include\wx\evtloop.h"\r
                                >\r
                        </File>\r
index 71959ce5f5b25383f3929a9575d0411820c8fa7e..7cb9c4efb5b5f3d35115789bb9bbd676889f9b05 100644 (file)
@@ -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):
 
index 0ea4a57464a97153b323b2c823723abada2dcc24..271c4b12071b7ecca47a10ae20415d3403b3bb66 100644 (file)
@@ -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
index a94c5375dfd8fd199a0f3d1b558c3ef776108990..70ea52e26e9abc95e137db4b62f630701890aeb7 100644 (file)
@@ -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 (file)
index 0000000..0aec4a3
--- /dev/null
@@ -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 <vadim@wxwidgets.org>
+// 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_
index c17ad1c002b1e1be86fda0ef4e2c6171a96eab94..82bffae0a3bfc193cd113b7ed26b47fe9a0d48b1 100644 (file)
@@ -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);
 
index 6262b8f36363e706f9d050cf4c4abeb35a6e0201..e61807c55d57a3957586b3862ff95a5ddc278de8 100644 (file)
@@ -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 (file)
index 0000000..4138f1f
--- /dev/null
@@ -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 <vadim@wxwidgets.org>
+// 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;
+};
index 194d0793acf80d32df46492c2bd49899f04e35e0..9ac78f57f6010213dc34169ec96703250464d4c9 100644 (file)
@@ -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)
index 31e6e6adef4f1cd523ee1ab455906a80c110870d..18e2386db02d0e179c91734a313ebec62d7e8daf 100644 (file)
@@ -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
         }
index 3dad0b791f9ec2a0c54fb99cf948df81f66deace..cd310242db9080ffa51f6d4c61dce065045664fa 100644 (file)
@@ -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
index c6a2a80ec7d4467f39aa146901e34f67476144b7..656e960308d879e3fd3d320634396130d7a1028c 100644 (file)
@@ -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
index 8d183a86914c1cc24c94b1674864e5dad2e9c418..8d0d4d5f288d69e6d82957f3da47d6878be259c2 100644 (file)
@@ -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