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

@@ -999,7 +999,21 @@ public:
// This is also used only internally by ProcessEvent() to check if it
// should process the event normally or only restrict the search for the
// event handler to this object itself.
bool ShouldProcessHereOnly() const { return m_processHereOnly; }
bool ShouldProcessOnlyIn(wxEvtHandler *h) const
{
return h == m_handlerToProcessOnlyIn;
}
// Called to indicate that the result of ShouldProcessOnlyIn() wasn't taken
// into account. The existence of this function may seem counterintuitive
// but unfortunately it's needed by wxScrollHelperEvtHandler, see comments
// there. Don't even think of using this in your own code, this is a gross
// hack and is only needed because of wx complicated history and should
// never be used anywhere else.
void DidntHonourProcessOnlyIn()
{
m_handlerToProcessOnlyIn = NULL;
}
protected:
wxObject* m_eventObject;
@@ -1011,6 +1025,10 @@ public:
// m_callbackUserData is for internal usage only
wxObject* m_callbackUserData;
private:
// If this handler
wxEvtHandler *m_handlerToProcessOnlyIn;
protected:
// the propagation level: while it is positive, we propagate the event to
// the parent window (if any)
@@ -1025,11 +1043,6 @@ protected:
// once for this event
bool m_wasProcessed;
// this flag is used by ProcessEventLocally() to prevent ProcessEvent()
// from doing its usual stuff and force it to just call TryHere() instead,
// see the comment there explaining why is this needed
bool m_processHereOnly;
protected:
wxEvent(const wxEvent&); // for implementing Clone()
wxEvent& operator=(const wxEvent&); // for derived classes operator=()
@@ -1038,8 +1051,8 @@ private:
// it needs to access our m_propagationLevel
friend class WXDLLIMPEXP_FWD_BASE wxPropagateOnce;
// and this one needs to access our m_processHereOnly
friend class WXDLLIMPEXP_FWD_BASE wxEventProcessHereOnly;
// and this one needs to access our m_handlerToProcessOnlyIn
friend class WXDLLIMPEXP_FWD_BASE wxEventProcessInHandlerOnly;
DECLARE_ABSTRACT_CLASS(wxEvent)
@@ -1093,31 +1106,28 @@ private:
wxDECLARE_NO_COPY_CLASS(wxPropagateOnce);
};
// A helper used by ProcessEventLocally() to restrict the event processing
// to this handler only.
class WXDLLIMPEXP_BASE wxEventProcessHereOnly
// A helper object used to temporarily make wxEvent::ShouldProcessOnlyIn()
// return true for the handler passed to its ctor.
class wxEventProcessInHandlerOnly
{
public:
wxEventProcessHereOnly(wxEvent& event) : m_event(event)
wxEventProcessInHandlerOnly(wxEvent& event, wxEvtHandler *handler)
: m_event(event),
m_handlerToProcessOnlyInOld(event.m_handlerToProcessOnlyIn)
{
// This would be unexpected and would also restore the wrong value in
// this class dtor so if even does happen legitimately we'd need to
// store the value in ctor and restore it in dtor.
wxASSERT_MSG( !m_event.m_processHereOnly,
"shouldn't be used twice for the same event" );
m_event.m_processHereOnly = true;
m_event.m_handlerToProcessOnlyIn = handler;
}
~wxEventProcessHereOnly()
~wxEventProcessInHandlerOnly()
{
m_event.m_processHereOnly = false;
m_event.m_handlerToProcessOnlyIn = m_handlerToProcessOnlyInOld;
}
private:
wxEvent& m_event;
wxEvtHandler * const m_handlerToProcessOnlyInOld;
wxDECLARE_NO_COPY_CLASS(wxEventProcessHereOnly);
wxDECLARE_NO_COPY_CLASS(wxEventProcessInHandlerOnly);
};
#if wxUSE_GUI