Fix recently broken forwarding of events between event handlers.

After the recent changes to the event processing logic, forwarding an event
from one event handler to another one stopped working correctly because the
per-event "process here only" flag prevented it from following the event
handler chain after forwarding. This notably broke keyboard navigation in
wxComboCtrl under MSW in wx itself and probably quite a few of other things in
user code.

Fix this by replacing the boolean flag with a pointer to the handler to which
the processing of this event should be restricted. This allows the full
processing to still take place if an event is forwarded to another handler.
So wxEvent::ShouldProcessHereOnly() is now called ShouldProcessOnlyIn() and
takes a wxEvtHandler parameter.

This made appear a problem in wxScrollHelperEvtHandler code that was hidden by
the bug above: the events were still processed multiple times in it. To fix
this, also add wxEvent::DidntHonourProcessOnlyIn() and take it into account in
the base class code. Did I mention that wxScrollHelperEvtHandler must die?

Add another unit test checking that forwarding works correctly.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64464 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2010-06-02 11:58:31 +00:00
parent ce6b1014bf
commit bbdee10d5f
4 changed files with 107 additions and 37 deletions

View File

@@ -363,10 +363,10 @@ wxEvent::wxEvent(int theId, wxEventType commandType)
m_id = theId;
m_skipped = false;
m_callbackUserData = NULL;
m_handlerToProcessOnlyIn = NULL;
m_isCommandEvent = false;
m_propagationLevel = wxEVENT_PROPAGATE_NONE;
m_wasProcessed = false;
m_processHereOnly = false;
}
wxEvent::wxEvent(const wxEvent& src)
@@ -376,11 +376,11 @@ wxEvent::wxEvent(const wxEvent& src)
, m_timeStamp(src.m_timeStamp)
, m_id(src.m_id)
, m_callbackUserData(src.m_callbackUserData)
, m_handlerToProcessOnlyIn(NULL)
, m_propagationLevel(src.m_propagationLevel)
, m_skipped(src.m_skipped)
, m_isCommandEvent(src.m_isCommandEvent)
, m_wasProcessed(false)
, m_processHereOnly(false)
{
}
@@ -393,11 +393,12 @@ wxEvent& wxEvent::operator=(const wxEvent& src)
m_timeStamp = src.m_timeStamp;
m_id = src.m_id;
m_callbackUserData = src.m_callbackUserData;
m_handlerToProcessOnlyIn = NULL;
m_propagationLevel = src.m_propagationLevel;
m_skipped = src.m_skipped;
m_isCommandEvent = src.m_isCommandEvent;
// don't change m_wasProcessed nor m_processHereOnly
// don't change m_wasProcessed
return *this;
}
@@ -1378,7 +1379,7 @@ bool wxEvtHandler::ProcessEvent(wxEvent& event)
// Short circuit the event processing logic if we're requested to process
// this event in this handler only, see DoTryChain() for more details.
if ( event.ShouldProcessHereOnly() )
if ( event.ShouldProcessOnlyIn(this) )
return TryHere(event);
@@ -1432,12 +1433,21 @@ bool wxEvtHandler::DoTryChain(wxEvent& event)
// window to be called.
//
// So we must call ProcessEvent() but it must not do what it usually
// does. To resolve this paradox we pass a special "process here only"
// flag to ProcessEvent() via the event object itself. This ensures
// that if our own, base class, version is called, it will just call
// TryHere() and won't do anything else, just as we want it to.
wxEventProcessHereOnly processHereOnly(event);
if ( h->ProcessEvent(event) )
// does. To resolve this paradox we set up a special flag inside the
// object itself to let ProcessEvent() know that it shouldn't do any
// pre/post-processing for this event if it gets it. Note that this
// only applies to this handler, if the event is passed to another one
// by explicitly calling its ProcessEvent(), pre/post-processing should
// be done as usual.
//
// Final complication is that if the implementation of ProcessEvent()
// called wxEvent::DidntHonourProcessOnlyIn() (as the gross hack that
// is wxScrollHelperEvtHandler::ProcessEvent() does) and ignored our
// request to process event in this handler only, we have to compensate
// for it by not processing the event further because this was already
// done by that rogue event handler.
wxEventProcessInHandlerOnly processInHandlerOnly(event, h);
if ( h->ProcessEvent(event) || !event.ShouldProcessOnlyIn(h) )
return true;
}