diff --git a/include/wx/window.h b/include/wx/window.h index fb66bf004e..84da1edd65 100644 --- a/include/wx/window.h +++ b/include/wx/window.h @@ -1651,8 +1651,9 @@ private: void NotifyWindowOnEnableChange(bool enabled); #if wxUSE_MENUS - // temporary event handler used by GetPopupMenuSelectionFromUser() + // temporary event handlers used by GetPopupMenuSelectionFromUser() void InternalOnPopupMenu(wxCommandEvent& event); + void InternalOnPopupMenuUpdate(wxUpdateUIEvent& event); // implementation of the public GetPopupMenuSelectionFromUser() method int DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y); diff --git a/interface/wx/window.h b/interface/wx/window.h index 4b7f8a7c0a..8f8a9d8364 100644 --- a/interface/wx/window.h +++ b/interface/wx/window.h @@ -1060,28 +1060,35 @@ public: */ wxWindow* GetParent() const; + //@{ /** This function shows a popup menu at the given position in this window and - returns the selected id. It can be more convenient than the general purpose - PopupMenu() function for simple menus proposing a choice in a list of - strings to the user. + returns the selected id. + + It can be more convenient than the general purpose PopupMenu() function + for simple menus proposing a choice in a list of strings to the user. + + Notice that to avoid unexpected conflicts between the (usually + consecutive range of) ids used by the menu passed to this function and + the existing EVT_UPDATE_UI() handlers, this function temporarily + disables UI updates for the window, so you need to manually disable + (or toggle or ...) any items which should be disabled in the menu + before showing it. @param menu - The menu to show + The menu to show. @param pos - The position at which to show the menu in client coordinates + The position at which to show the menu in client coordinates. - @return The selected menu item id or wxID_NONE if none selected or an - error occurred. + @return + The selected menu item id or @c wxID_NONE if none selected or an + error occurred. + + @since 2.9.0 */ int GetPopupMenuSelectionFromUser(wxMenu& menu, const wxPoint& pos); - - /** - See the GetPopupMenuSelectionFromUser(wxMenu&, const wxPoint&) overload. - This overload differs only because it takes two integers for the - menu position instead of a wxPoint. - */ int GetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y); + //@} /** This gets the position of the window in pixels, relative to the parent window diff --git a/src/common/wincmn.cpp b/src/common/wincmn.cpp index 6eac63e1a9..a519ffd7f0 100644 --- a/src/common/wincmn.cpp +++ b/src/common/wincmn.cpp @@ -2407,6 +2407,11 @@ void wxWindowBase::InternalOnPopupMenu(wxCommandEvent& event) gs_popupMenuSelection = event.GetId(); } +void wxWindowBase::InternalOnPopupMenuUpdate(wxUpdateUIEvent& WXUNUSED(event)) +{ + // nothing to do but do not skip it +} + int wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y) { @@ -2417,8 +2422,24 @@ wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y) NULL, this); + // it is common to construct the menu passed to this function dynamically + // using some fixed range of ids which could clash with the ids used + // elsewhere in the program, which could result in some menu items being + // unintentionally disabled or otherwise modified by update UI handlers + // elsewhere in the program code and this is difficult to avoid in the + // program itself, so instead we just temporarily suspend UI updating while + // this menu is shown + Connect(wxEVT_UPDATE_UI, + wxUpdateUIEventHandler(wxWindowBase::InternalOnPopupMenuUpdate), + NULL, + this); + PopupMenu(&menu, x, y); + Disconnect(wxEVT_UPDATE_UI, + wxUpdateUIEventHandler(wxWindowBase::InternalOnPopupMenuUpdate), + NULL, + this); Disconnect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu), NULL,