diff --git a/include/wx/docview.h b/include/wx/docview.h index 3a4238fa5b..78bf44d4b4 100644 --- a/include/wx/docview.h +++ b/include/wx/docview.h @@ -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: diff --git a/src/common/docview.cpp b/src/common/docview.cpp index 341ec7cb2a..b646d9efe2 100644 --- a/src/common/docview.cpp +++ b/src/common/docview.cpp @@ -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); }