From 29de6f400ce48a9ce52c4aa900d8d1edb178d5ba Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 16 Jan 2009 16:07:16 +0000 Subject: [PATCH] ensure that ProcessEvent() is called for all the event handlers, not just the first one in event handlers list git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58144 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/event.h | 29 ++++++++++++++++------ src/common/event.cpp | 59 +++++++++++++++++++++++++++----------------- 2 files changed, 58 insertions(+), 30 deletions(-) diff --git a/include/wx/event.h b/include/wx/event.h index 369c0b9da9..e88450a8a2 100644 --- a/include/wx/event.h +++ b/include/wx/event.h @@ -718,7 +718,7 @@ public: void Skip(bool skip = true) { m_skipped = skip; } bool GetSkipped() const { return m_skipped; } - // this function is used to create a copy of the event polymorphically and + // This function is used to create a copy of the event polymorphically and // all derived classes must implement it because otherwise wxPostEvent() // for them wouldn't work (it needs to do a copy of the event) virtual wxEvent *Clone() const = 0; @@ -747,6 +747,20 @@ public: m_propagationLevel = propagationLevel; } + + // This is for internal use only and is only called by + // wxEvtHandler::ProcessEvent() to check whether it's the first time this + // event is being processed + bool WasProcessed() + { + if ( m_wasProcessed ) + return true; + + m_wasProcessed = true; + + return false; + } + protected: wxObject* m_eventObject; wxEventType m_eventType; @@ -768,6 +782,12 @@ protected: bool m_skipped; bool m_isCommandEvent; + // initially false but becomes true as soon as WasProcessed() is called for + // the first time, as this is done only by ProcessEvent() it explains the + // variable name: it becomes true after ProcessEvent() was called at least + // once for this event + bool m_wasProcessed; + protected: wxEvent(const wxEvent&); // for implementing Clone() wxEvent& operator=(const wxEvent&); // for derived classes operator=() @@ -3081,12 +3101,7 @@ public: void OnSinkDestroyed( wxEvtHandler *sink ); - // The method processing the event in this event handler (or rather in this - // event handler chain as it also tries the next handler and so on), i.e. - // it returns true if we processed this event or false if we didn't but - // does not call TryParent() in the latter case. It also doesn't call - // wxApp::FilterEvent() before processing it, this is supposed to be done - // by the public ProcessEvent() only once for every event we handle. + // The method tries to process the event in this event handler. // // It is meant to be called from ProcessEvent() only and is not virtual, // additional event handlers can be hooked into the normal event processing diff --git a/src/common/event.cpp b/src/common/event.cpp index 700084e9cc..3ee0d136ed 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -352,6 +352,7 @@ wxEvent::wxEvent(int theId, wxEventType commandType ) m_callbackUserData = NULL; m_isCommandEvent = false; m_propagationLevel = wxEVENT_PROPAGATE_NONE; + m_wasProcessed = false; } wxEvent::wxEvent(const wxEvent& src) @@ -364,6 +365,7 @@ wxEvent::wxEvent(const wxEvent& src) , m_propagationLevel(src.m_propagationLevel) , m_skipped(src.m_skipped) , m_isCommandEvent(src.m_isCommandEvent) + , m_wasProcessed(false) { } @@ -380,6 +382,8 @@ wxEvent& wxEvent::operator=(const wxEvent& src) m_skipped = src.m_skipped; m_isCommandEvent = src.m_isCommandEvent; + // don't change m_wasProcessed + return *this; } @@ -1263,22 +1267,35 @@ bool wxEvtHandler::TryParent(wxEvent& event) bool wxEvtHandler::ProcessEvent(wxEvent& event) { // allow the application to hook into event processing - if ( wxTheApp ) + // + // 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() ) { - int rc = wxTheApp->FilterEvent(event); - if ( rc != -1 ) + if ( wxTheApp ) { - wxASSERT_MSG( rc == 1 || rc == 0, - _T("unexpected wxApp::FilterEvent return value") ); + int rc = wxTheApp->FilterEvent(event); + if ( rc != -1 ) + { + wxASSERT_MSG( rc == 1 || rc == 0, + "unexpected wxApp::FilterEvent return value" ); - return rc != 0; + return rc != 0; + } + //else: proceed normally } - //else: proceed normally } if ( ProcessEventHere(event) ) return true; + // pass the event to the next handler, notice that we shouldn't call + // TryParent() even if it doesn't handle the event as the last handler in + // the chain will do it + if ( GetNextHandler() ) + return GetNextHandler()->ProcessEvent(event); + // propagate the event upwards the window chain and/or to the application // object if it wasn't processed at this level return TryParent(event); @@ -1286,25 +1303,21 @@ bool wxEvtHandler::ProcessEvent(wxEvent& event) bool wxEvtHandler::ProcessEventHere(wxEvent& event) { - // An event handler can be enabled or disabled - if ( GetEvtHandlerEnabled() ) - { - // if we have a validator, it has higher priority than our own event - // table - if ( TryValidator(event) ) - return true; + // If the event handler is disabled it doesn't process any events + if ( !GetEvtHandlerEnabled() ) + return false; - // Handle per-instance dynamic event tables first - if ( m_dynamicEvents && SearchDynamicEventTable(event) ) - return true; + // If we have a validator, it has higher priority than our own event + // handlers + if ( TryValidator(event) ) + return true; - // Then static per-class event tables - if ( GetEventHashTable().HandleEvent(event, this) ) - return true; - } + // Handle per-instance dynamic event tables first + if ( m_dynamicEvents && SearchDynamicEventTable(event) ) + return true; - // Try going down the event handler chain - if ( GetNextHandler() && GetNextHandler()->ProcessEventHere(event) ) + // Then static per-class event tables + if ( GetEventHashTable().HandleEvent(event, this) ) return true; // We don't have a handler for this event. -- 2.45.2