diff --git a/include/wx/menu.h b/include/wx/menu.h index 876a72e162..1a5ef27737 100644 --- a/include/wx/menu.h +++ b/include/wx/menu.h @@ -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; } diff --git a/src/common/menucmn.cpp b/src/common/menucmn.cpp index 5f7c8cd9b4..76f17e9481 100644 --- a/src/common/menucmn.cpp +++ b/src/common/menucmn.cpp @@ -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 // ---------------------------------------------------------------------------- diff --git a/src/msw/menu.cpp b/src/msw/menu.cpp index ab1ada1220..7c62184ce2 100644 --- a/src/msw/menu.cpp +++ b/src/msw/menu.cpp @@ -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(); } // --------------------------------------------------------------------------- diff --git a/src/univ/menu.cpp b/src/univ/menu.cpp index eaf34b8f9e..4714ba73f3 100644 --- a/src/univ/menu.cpp +++ b/src/univ/menu.cpp @@ -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);