Avoid dropping events in wxDocParentFrameAnyBase in some circumstances.
The code trying to avoid forwarding duplicate events to wxDocManager was over eager and in some situations filtered out the events which hadn't been sent to it yet and were, in fact, not handled at all. This could be seen, for example, by running the docview sample with "--sdi" command line option, creating one child frame and then trying to create another one from the parent frame menu: this failed because the existence of a valid child was considered to be enough for the event to have been already processed in it which was false in this case. Unfortunately there is no obvious fix to this problem, notably because of the very roundabout way the toolbar events are processed in MDI windows: the toolbar itself is a child of the parent frame but the events from it are still sent to the currently active child frame by wxMDIParentFrameBase. So we can't rely on any kind of parent-of-originating-window checks. Instead, remember the last event handled in the child and avoid processing the same event in wxDocManager again. This should at least avoid the false positives (like the one fixed by this commit), although it could still result in false negatives (i.e. some duplicated events) if an event handler generated other events while skipping the original one. This is a lesser evil though and should be relatively rare in practice, so live with this ugliness until someone comes with another idea of fixing the bug described above. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74919 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
736692f3a4
commit
e118367990
@ -279,6 +279,9 @@ public:
|
||||
// destroyed
|
||||
void SetDocChildFrame(wxDocChildFrameAnyBase *docChildFrame);
|
||||
|
||||
// get the associated frame, may be NULL during destruction
|
||||
wxDocChildFrameAnyBase* GetDocChildFrame() const { return m_docChildFrame; }
|
||||
|
||||
protected:
|
||||
// hook the document into event handlers chain here
|
||||
virtual bool TryBefore(wxEvent& event);
|
||||
@ -597,6 +600,7 @@ public:
|
||||
m_childDocument = NULL;
|
||||
m_childView = NULL;
|
||||
m_win = NULL;
|
||||
m_lastEvent = NULL;
|
||||
}
|
||||
|
||||
// full ctor equivalent to using the default one and Create()
|
||||
@ -638,6 +642,14 @@ public:
|
||||
|
||||
wxWindow *GetWindow() const { return m_win; }
|
||||
|
||||
// implementation only
|
||||
|
||||
// Check if this event had been just processed in this frame.
|
||||
bool HasAlreadyProcessed(wxEvent& event) const
|
||||
{
|
||||
return m_lastEvent == &event;
|
||||
}
|
||||
|
||||
protected:
|
||||
// we're not a wxEvtHandler but we provide this wxEvtHandler-like function
|
||||
// which is called from TryBefore() of the derived classes to give our view
|
||||
@ -656,6 +668,10 @@ protected:
|
||||
// allows us to avoid having any virtual functions in this class
|
||||
wxWindow* m_win;
|
||||
|
||||
private:
|
||||
// Pointer to the last processed event used to avoid sending the same event
|
||||
// twice to wxDocManager, from here and from wxDocParentFrameAnyBase.
|
||||
wxEvent* m_lastEvent;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxDocChildFrameAnyBase);
|
||||
};
|
||||
@ -894,7 +910,11 @@ protected:
|
||||
// hook the document manager into event handling chain here
|
||||
virtual bool TryBefore(wxEvent& event)
|
||||
{
|
||||
return TryProcessEvent(event) || BaseFrame::TryBefore(event);
|
||||
// It is important to send the event to the base class first as
|
||||
// wxMDIParentFrame overrides its TryBefore() to send the menu events
|
||||
// to the currently active child frame and the child must get them
|
||||
// before our own TryProcessEvent() is executed, not afterwards.
|
||||
return BaseFrame::TryBefore(event) || TryProcessEvent(event);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -2027,6 +2027,11 @@ bool wxDocChildFrameAnyBase::TryProcessEvent(wxEvent& event)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store a (non-owning) pointer to the last processed event here to be able
|
||||
// to recognize this event again if it bubbles up to the parent frame, see
|
||||
// the code in wxDocParentFrameAnyBase::TryProcessEvent().
|
||||
m_lastEvent = &event;
|
||||
|
||||
// Forward the event to the document manager which will, in turn, forward
|
||||
// it to its active view which must be our m_childView.
|
||||
//
|
||||
@ -2079,28 +2084,13 @@ bool wxDocParentFrameAnyBase::TryProcessEvent(wxEvent& event)
|
||||
// already forwarded the event to wxDocManager, check for this:
|
||||
if ( wxView* const view = m_docManager->GetAnyUsableView() )
|
||||
{
|
||||
wxWindow* win = view->GetFrame();
|
||||
if ( win && win != m_frame )
|
||||
{
|
||||
// Notice that we intentionally don't use wxGetTopLevelParent()
|
||||
// here because we want to check both for the case of a child
|
||||
// "frame" (e.g. MDI child frame or notebook page) inside this TLW
|
||||
// and a separate child TLW frame (as used in the SDI mode) here.
|
||||
for ( win = win->GetParent(); win; win = win->GetParent() )
|
||||
{
|
||||
if ( win == m_frame )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//else: This view is directly associated with the parent frame (which
|
||||
// can happen in the so called "single" mode in which only one
|
||||
// document can be opened and so is managed by the parent frame
|
||||
// itself), there can be no child frame in play so we must forward
|
||||
// the event to wxDocManager ourselves.
|
||||
wxDocChildFrameAnyBase* const childFrame = view->GetDocChildFrame();
|
||||
if ( childFrame && childFrame->HasAlreadyProcessed(event) )
|
||||
return false;
|
||||
}
|
||||
|
||||
// But forward the event to wxDocManager ourselves if there are no views at
|
||||
// all or if we are the frame's view ourselves.
|
||||
// all or if this event hadn't been sent to the child frame previously.
|
||||
return m_docManager->ProcessEventLocally(event);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user