diff --git a/include/wx/taskbar.h b/include/wx/taskbar.h index c209a1027b..84e4a5c0b0 100644 --- a/include/wx/taskbar.h +++ b/include/wx/taskbar.h @@ -59,9 +59,16 @@ public: void Destroy(); protected: + // Note: only one of the following functions should be overridden, if both + // of them are, GetPopupMenu() has the priority, i.e. CreatePopupMenu() + // won't be called if GetPopupMenu() returns a non-null pointer. + // creates menu to be displayed when user clicks on the icon virtual wxMenu *CreatePopupMenu() { return NULL; } + // same as CreatePopupMenu but the returned menu won't be destroyed + virtual wxMenu *GetPopupMenu() { return NULL; } + private: // default events handling, calls CreatePopupMenu: void OnRightButtonDown(wxTaskBarIconEvent& event); diff --git a/interface/wx/taskbar.h b/interface/wx/taskbar.h index a7ad602dd9..d9e2183b8d 100644 --- a/interface/wx/taskbar.h +++ b/interface/wx/taskbar.h @@ -62,8 +62,9 @@ public: @beginEventEmissionTable{wxTaskBarIconEvent} Note that not all ports are required to send these events and so it's better - to override wxTaskBarIcon::CreatePopupMenu() if all that the application does - is that it shows a popup menu in reaction to mouse click. + to override wxTaskBarIcon::CreatePopupMenu() or wxTaskBarIcon::GetPopupMenu() + if all that the application does is that it shows a popup menu in reaction to + mouse click. @event{EVT_TASKBAR_MOVE(func)} Process a @c wxEVT_TASKBAR_MOVE event. @event{EVT_TASKBAR_LEFT_DOWN(func)} @@ -123,9 +124,10 @@ public: The events can be handled by a class derived from wxTaskBarIcon. @note - It is recommended to override CreatePopupMenu() callback instead of - calling this method from event handler, because some ports (e.g. wxCocoa) - may not implement PopupMenu() and mouse click events at all. + It is recommended to override the CreatePopupMenu() or GetPopupMenu() + callback instead of calling this method from event handler, because some + ports (e.g. wxCocoa) may not implement PopupMenu() and mouse click events + at all. */ virtual bool PopupMenu(wxMenu* menu); @@ -166,17 +168,37 @@ public: protected: /** - This method is called by the library when the user requests popup menu - (on Windows and Unix platforms, this is when the user right-clicks the icon). + Called by the library when the user requests popup menu if + GetPopupMenu() is not overridden. - Override this function in order to provide popup menu associated with the icon. - If CreatePopupMenu() returns @NULL (this happens by default), no menu is shown, - otherwise the menu is displayed and then deleted by the library as soon as the - user dismisses it. + Override this function in order to provide popup menu associated with + the icon if you don't want to override GetPopupMenu(), i.e. if you + prefer creating a new menu every time instead of reusing the same menu. - The events can be handled by a class derived from wxTaskBarIcon. + If CreatePopupMenu() returns @NULL (this happens by default), no menu + is shown, otherwise the menu is displayed and then deleted by the + library as soon as the user dismisses it. If you don't want the menu to + be destroyed when it is dismissed, override GetPopupMenu() instead. */ virtual wxMenu* CreatePopupMenu(); + + /** + Called by the library when the user requests popup menu. + + On Windows and Unix platforms this happens when the user right-clicks + the icon, so overriding this method is the simplest way to implement + the standard behaviour of showing a menu when the taskbar icon is + clicked. + + If GetPopupMenu() returns @NULL (this happens by default), + CreatePopupMenu() is called next and its menu is used (if non-@NULL). + Otherwise the menu returned by GetPopupMenu() is shown and, contrary to + CreatePopupMenu(), not destroyed when the user dismisses it, allowing + to reuse the same menu pointer multiple times. + + @since 3.1.5 + */ + virtual wxMenu* GetPopupMenu(); }; diff --git a/src/common/taskbarcmn.cpp b/src/common/taskbarcmn.cpp index cc5908ad06..ef2a2927e7 100644 --- a/src/common/taskbarcmn.cpp +++ b/src/common/taskbarcmn.cpp @@ -25,6 +25,8 @@ #include "wx/menu.h" #endif +#include "wx/scopedptr.h" + extern WXDLLIMPEXP_DATA_BASE(wxList) wxPendingDelete; // DLL options compatibility check: @@ -47,12 +49,18 @@ wxEND_EVENT_TABLE() void wxTaskBarIconBase::OnRightButtonDown(wxTaskBarIconEvent& WXUNUSED(event)) { - wxMenu *menu = CreatePopupMenu(); - if (menu) + wxScopedPtr menuDeleter; + wxMenu *menu = GetPopupMenu(); + if ( !menu ) { - PopupMenu(menu); - delete menu; + menu = CreatePopupMenu(); + if ( !menu ) + return; + + menuDeleter.reset(menu); } + + PopupMenu(menu); } void wxTaskBarIconBase::Destroy() diff --git a/src/osx/cocoa/taskbar.mm b/src/osx/cocoa/taskbar.mm index df66491361..14c80efb51 100644 --- a/src/osx/cocoa/taskbar.mm +++ b/src/osx/cocoa/taskbar.mm @@ -19,6 +19,7 @@ #include "wx/dcclient.h" #endif +#include "wx/scopedptr.h" #include "wx/taskbar.h" #include "wx/osx/private.h" @@ -68,6 +69,8 @@ public: inline wxTaskBarIcon* GetTaskBarIcon() { return m_taskBarIcon; } wxMenu * CreatePopupMenu() { return m_taskBarIcon->CreatePopupMenu(); } + wxMenu * GetPopupMenu() + { return m_taskBarIcon->GetPopupMenu(); } wxDECLARE_NO_COPY_CLASS(wxTaskBarIconImpl); @@ -100,6 +103,7 @@ protected: private: wxTaskBarIconDockImpl(); wxMenu *m_pMenu; + wxScopedPtr m_menuDeleter; }; class wxTaskBarIconCustomStatusItemImpl; @@ -246,20 +250,25 @@ WX_NSMenu wxTaskBarIconDockImpl::OSXGetDockHMenu() WX_NSMenu wxTaskBarIconDockImpl::OSXDoGetDockHMenu() { - wxMenu *dockMenu = CreatePopupMenu(); + m_menuDeleter.reset(); - if(!dockMenu) - return nil; - - wxDELETE(m_pMenu); + m_pMenu = GetPopupMenu(); + + if (!m_pMenu) + { + m_pMenu = CreatePopupMenu(); + + if (!m_pMenu) + return nil; + + m_menuDeleter.reset(m_pMenu); + } - m_pMenu = dockMenu; - m_pMenu->SetInvokingWindow(m_eventWindow); m_pMenu->UpdateUI(); - return (WX_NSMenu)dockMenu->GetHMenu(); + return (WX_NSMenu)m_pMenu->GetHMenu(); } bool wxTaskBarIconDockImpl::SetIcon(const wxIcon& icon, const wxString& WXUNUSED(tooltip)) @@ -271,7 +280,8 @@ bool wxTaskBarIconDockImpl::SetIcon(const wxIcon& icon, const wxString& WXUNUSED bool wxTaskBarIconDockImpl::RemoveIcon() { - wxDELETE(m_pMenu); + m_menuDeleter.reset(); + m_icon = wxBitmap(); [[NSApplication sharedApplication] setApplicationIconImage:nil]; return true;