]> git.saurik.com Git - wxWidgets.git/commitdiff
Prevent duplicate menu event processing in MDI windows.
authorVadim Zeitlin <vadim@wxwidgets.org>
Wed, 3 Jul 2013 22:18:42 +0000 (22:18 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Wed, 3 Jul 2013 22:18:42 +0000 (22:18 +0000)
Record the object propagating the given event upwards in the event object
itself and use it in wxMDIParentFrame to determine whether the event being
handled is already coming from wxMDIChildFrame and avoid sending it back for
processing it there again in this case.

This is ugly and makes wx event processing even more complex but this is the
only way I could find to ensure that

(a) Both the child and the parent frames get the events from the toolbar
    (even though the toolbar parent is the parent frame and hence normally
    the child wouldn't get notified about them at all and so the forwarding
    at wxMDIParentFrame level is required to make this work).

(b) The child gets the event only once, whether it comes from a toolbar (and
    hence indirectly via the parent frame) or from the child menu (and hence
    directly to the child, at least in wxMSW).

This commit fixes the event propagation unit test case, at least under MSW and
GTK.

See #14314.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74357 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/event.h
include/wx/mdi.h
src/common/event.cpp
src/common/wincmn.cpp

index 38303aaae61cf1aeff5f703e9a864d432ceec7cb..874d42e2746cf96859ed1b93d86c1bdd826f8e08 100644 (file)
@@ -986,6 +986,9 @@ public:
         m_propagationLevel = propagationLevel;
     }
 
+    // This method is for internal use only and allows to get the object that
+    // is propagating this event upwards the window hierarchy, if any.
+    wxEvtHandler* GetPropagatedFrom() const { return m_propagatedFrom; }
 
     // This is for internal use only and is only called by
     // wxEvtHandler::ProcessEvent() to check whether it's the first time this
@@ -1056,6 +1059,10 @@ protected:
     // the parent window (if any)
     int               m_propagationLevel;
 
+    // The object that the event is being propagated from, initially NULL and
+    // only set by wxPropagateOnce.
+    wxEvtHandler*     m_propagatedFrom;
+
     bool              m_skipped;
     bool              m_isCommandEvent;
 
@@ -1075,7 +1082,7 @@ protected:
     wxEvent& operator=(const wxEvent&); // for derived classes operator=()
 
 private:
-    // it needs to access our m_propagationLevel
+    // It needs to access our m_propagationLevel and m_propagatedFrom fields.
     friend class WXDLLIMPEXP_FWD_BASE wxPropagateOnce;
 
     // and this one needs to access our m_handlerToProcessOnlyIn
@@ -1109,26 +1116,35 @@ private:
 };
 
 /*
- * Another one to temporarily lower propagation level.
+ * Helper used to indicate that an event is propagated upwards the window
+ * hierarchy by the given window.
  */
 class WXDLLIMPEXP_BASE wxPropagateOnce
 {
 public:
-    wxPropagateOnce(wxEvent& event) : m_event(event)
+    // The handler argument should normally be non-NULL to allow the parent
+    // event handler to know that it's being used to process an event coming
+    // from the child, it's only NULL by default for backwards compatibility.
+    wxPropagateOnce(wxEvent& event, wxEvtHandler* handler = NULL)
+        : m_event(event),
+          m_propagatedFromOld(event.m_propagatedFrom)
     {
         wxASSERT_MSG( m_event.m_propagationLevel > 0,
                         wxT("shouldn't be used unless ShouldPropagate()!") );
 
         m_event.m_propagationLevel--;
+        m_event.m_propagatedFrom = handler;
     }
 
     ~wxPropagateOnce()
     {
+        m_event.m_propagatedFrom = m_propagatedFromOld;
         m_event.m_propagationLevel++;
     }
 
 private:
     wxEvent& m_event;
+    wxEvtHandler* const m_propagatedFromOld;
 
     wxDECLARE_NO_COPY_CLASS(wxPropagateOnce);
 };
index 78c2f4c3e47c65f37a05dc153684dd0dcfe38310..52cbed7da4de1516e65f162f6f081a4ab9dab915 100644 (file)
@@ -381,8 +381,18 @@ inline bool wxMDIParentFrameBase::TryBefore(wxEvent& event)
             event.GetEventType() == wxEVT_UPDATE_UI )
     {
         wxMDIChildFrame * const child = GetActiveChild();
-        if ( child && child->ProcessWindowEventLocally(event) )
-            return true;
+        if ( child )
+        {
+            // However avoid sending the event back to the child if it's
+            // currently being propagated to us from it.
+            wxWindow* const
+                from = static_cast<wxWindow*>(event.GetPropagatedFrom());
+            if ( !from || !from->IsDescendant(child) )
+            {
+                if ( child->ProcessWindowEventLocally(event) )
+                    return true;
+            }
+        }
     }
 
     return wxFrame::TryBefore(event);
index 2733450352c406cee3678be9b364f69837c9df7e..c9e8f11bcadbec2604eac1db6935074c20d77c1a 100644 (file)
@@ -369,6 +369,7 @@ wxEvent::wxEvent(int theId, wxEventType commandType)
     m_handlerToProcessOnlyIn = NULL;
     m_isCommandEvent = false;
     m_propagationLevel = wxEVENT_PROPAGATE_NONE;
+    m_propagatedFrom = NULL;
     m_wasProcessed = false;
     m_willBeProcessedAgain = false;
 }
@@ -382,6 +383,7 @@ wxEvent::wxEvent(const wxEvent& src)
     , m_callbackUserData(src.m_callbackUserData)
     , m_handlerToProcessOnlyIn(NULL)
     , m_propagationLevel(src.m_propagationLevel)
+    , m_propagatedFrom(NULL)
     , m_skipped(src.m_skipped)
     , m_isCommandEvent(src.m_isCommandEvent)
     , m_wasProcessed(false)
@@ -400,6 +402,7 @@ wxEvent& wxEvent::operator=(const wxEvent& src)
     m_callbackUserData = src.m_callbackUserData;
     m_handlerToProcessOnlyIn = NULL;
     m_propagationLevel = src.m_propagationLevel;
+    m_propagatedFrom = NULL;
     m_skipped = src.m_skipped;
     m_isCommandEvent = src.m_isCommandEvent;
 
index 3c2c0f4e1d363f6264f3babe188074d2ebb1670a..787d08b13f8eddff990b6dd5c2979f413cddd6fc 100644 (file)
@@ -3370,7 +3370,7 @@ bool wxWindowBase::TryAfter(wxEvent& event)
             wxWindow *parent = GetParent();
             if ( parent && !parent->IsBeingDeleted() )
             {
-                wxPropagateOnce propagateOnce(event);
+                wxPropagateOnce propagateOnce(event, this);
 
                 return parent->GetEventHandler()->ProcessEvent(event);
             }