]> git.saurik.com Git - wxWidgets.git/commitdiff
Return correct invoking window for submenus of a popup menu.
authorVadim Zeitlin <vadim@wxwidgets.org>
Thu, 22 Apr 2010 11:21:35 +0000 (11:21 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Thu, 22 Apr 2010 11:21:35 +0000 (11:21 +0000)
SetInvokingWindow() is only called for the top menu being popped up itself but
the invoking window should also be associated with its submenus.

Modify GetInvokingWindow() to return the parents invoking window for submenus.

This fixes a crash due to returning NULL from wxMenu::GetWindow() in wxMSW
owner-drawn code.

And it also makes redundant some code in wxUniversal wxMenu implementation
which can now simply use GetInvokingWindow() in all cases.

Closes #11957.

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

include/wx/menu.h
src/common/menucmn.cpp
src/msw/menu.cpp
src/univ/menu.cpp

index 876a72e1622568fa47dcd0538b11bb2b48c9d803..1a5ef27737e77b040817cba080fdf6a7136338d0 100644 (file)
@@ -254,9 +254,12 @@ public:
     void SetEventHandler(wxEvtHandler *handler) { m_eventHandler = handler; }
     wxEvtHandler *GetEventHandler() const { return m_eventHandler; }
 
-    // invoking window
-    void SetInvokingWindow(wxWindow *win) { m_invokingWindow = win; }
-    wxWindow *GetInvokingWindow() const { return m_invokingWindow; }
+    // Invoking window: this is set by wxWindow::PopupMenu() before showing a
+    // popup menu and reset after it's hidden. Notice that GetInvokingWindow()
+    // recurses upwards and will return the invoking window for any submenu of
+    // a popup menu as well as the menu itself.
+    void SetInvokingWindow(wxWindow *win);
+    wxWindow *GetInvokingWindow() const;
 
     // style
     long GetStyle() const { return m_style; }
index 5f7c8cd9b446156264bcdb5be47c8c31b767e3e1..76f17e9481874f5de903c7782fc50bfb2db97936 100644 (file)
@@ -512,6 +512,34 @@ void wxMenuBase::Detach()
     m_menuBar = NULL;
 }
 
+// ----------------------------------------------------------------------------
+// wxMenu invoking window handling
+// ----------------------------------------------------------------------------
+
+void wxMenuBase::SetInvokingWindow(wxWindow *win)
+{
+    wxASSERT_MSG( !GetParent(),
+                    "should only be called for top level popup menus" );
+    wxASSERT_MSG( !IsAttached(),
+                    "menus attached to menu bar can't have invoking window" );
+
+    m_invokingWindow = win;
+}
+
+wxWindow *wxMenuBase::GetInvokingWindow() const
+{
+    // only the popup menu itself has a non-NULL invoking window so recurse
+    // upwards until we find it
+    const wxMenuBase *menu = this;
+    while ( menu->GetParent() )
+    {
+        menu = menu->GetParent();
+    }
+
+    // menu is a top level menu here
+    return menu->m_invokingWindow;
+}
+
 // ----------------------------------------------------------------------------
 // wxMenu functions forwarded to wxMenuItem
 // ----------------------------------------------------------------------------
index ab1ada12200adf415a6d169abfea98dd8a0ee63a..7c62184ce2bcf2607f6f032dc8c2b857be84f9b6 100644 (file)
@@ -984,12 +984,7 @@ bool wxMenu::MSWCommand(WXUINT WXUNUSED(param), WXWORD id_)
 
 wxWindow *wxMenu::GetWindow() const
 {
-    if ( m_invokingWindow != NULL )
-        return m_invokingWindow;
-    else if ( GetMenuBar() != NULL)
-        return GetMenuBar()->GetFrame();
-
-    return NULL;
+    return GetMenuBar() ? GetMenuBar()->GetFrame() : GetInvokingWindow();
 }
 
 // ---------------------------------------------------------------------------
index eaf34b8f9e79b531bf368c26d2a557aa05aa3fc9..4714ba73f3464a2d6461f6defb26f03633a8751f 100644 (file)
@@ -1114,13 +1114,6 @@ void wxMenu::OnItemAdded(wxMenuItem *item)
 #if wxUSE_ACCEL
     AddAccelFor(item);
 #endif // wxUSE_ACCEL
-
-    // the submenus of a popup menu should have the same invoking window as it
-    // has
-    if ( m_invokingWindow && item->IsSubMenu() )
-    {
-        item->GetSubMenu()->SetInvokingWindow(m_invokingWindow);
-    }
 }
 
 void wxMenu::EndRadioGroup()
@@ -1231,45 +1224,7 @@ void wxMenu::Detach()
 
 wxWindow *wxMenu::GetRootWindow() const
 {
-    if ( GetMenuBar() )
-    {
-        // simple case - a normal menu attached to the menubar
-        return GetMenuBar();
-    }
-
-    // we're a popup menu but the trouble is that only the top level popup menu
-    // has a pointer to the invoking window, so we must walk up the menu chain
-    // if needed
-    wxWindow *win = GetInvokingWindow();
-    if ( win )
-    {
-        // we already have it
-        return win;
-    }
-
-    wxMenu *menu = GetParent();
-    while ( menu )
-    {
-        // We are a submenu of a menu of a menubar
-        if (menu->GetMenuBar())
-           return menu->GetMenuBar();
-
-        win = menu->GetInvokingWindow();
-        if ( win )
-            break;
-
-        menu = menu->GetParent();
-    }
-
-    // we're probably going to crash in the caller anyhow, but try to detect
-    // this error as soon as possible
-    wxASSERT_MSG( win, wxT("menu without any associated window?") );
-
-    // also remember it in this menu so that we don't have to search for it the
-    // next time
-    wxConstCast(this, wxMenu)->m_invokingWindow = win;
-
-    return win;
+    return GetMenuBar() ? GetMenuBar() : GetInvokingWindow();
 }
 
 wxRenderer *wxMenu::GetRenderer() const
@@ -1338,12 +1293,10 @@ void wxMenu::OnDismiss(bool dismissParent)
         }
         else // popup menu
         {
-            wxCHECK_RET( m_invokingWindow, wxT("what kind of menu is this?") );
+            wxWindow * const win = GetInvokingWindow();
+            wxCHECK_RET( win, wxT("what kind of menu is this?") );
 
-            m_invokingWindow->DismissPopupMenu();
-
-            // Why reset it here? We need it for sending the event to...
-            // SetInvokingWindow(NULL);
+            win->DismissPopupMenu();
         }
     }
 }
@@ -2420,8 +2373,6 @@ void wxMenuBar::PopupCurrentMenu(bool selectFirst)
             // item, not to the right of it
             wxRect rectItem = GetItemRect(m_current);
 
-            m_menuShown->SetInvokingWindow(m_frameLast);
-
             m_menuShown->Popup(ClientToScreen(rectItem.GetPosition()),
                                wxSize(0, rectItem.GetHeight()),
                                selectFirst);