From: Václav Slavík Date: Tue, 23 Mar 2004 23:20:16 +0000 (+0000) Subject: unified wxTaskBarIcon behaviour: wxMSW version is not removed automatically when... X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/1e6d9c20fdb220e4cb9c1ee2a52709b08bb414ba unified wxTaskBarIcon behaviour: wxMSW version is not removed automatically when all frames are closed, it must be destroyed explicitly git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@26318 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/docs/changes.txt b/docs/changes.txt index de361734a9..7d11040915 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -39,6 +39,12 @@ INCOMPATIBLE CHANGES SINCE 2.4.x - wxChoice and wxCombobox now handle their size in the same way as in all the other ports under MSW, new code is actually correct but different from weird stuff they were doing before so the behaviour of your programs might change +- wxTaskBarIcon objects must now be destroyed before the application can exit. + Previously, the application terminated if there were no top level windows; + now it terminates if there are no top level windows or taskbar icons left. + +wxTaskBarIcon must be explicitly destroyed now, otherwise the application + won't exit even though there are no top level windows DEPRECATED METHODS SINCE 2.4.x @@ -92,6 +98,8 @@ wxMSW: - wxMenuBar::GetLabelTop() doesn't include '&'s in the label any more - wxRegConf couldn't read global settings without admin privileges and didn't even try to do it by default -- now it does +- wxTaskBarIcon must be explicitly destroyed now, otherwise the application + won't exit even though there are no top level windows wxMotif: diff --git a/include/wx/msw/taskbar.h b/include/wx/msw/taskbar.h index 9aa9bd1b33..d36e055b5c 100644 --- a/include/wx/msw/taskbar.h +++ b/include/wx/msw/taskbar.h @@ -3,7 +3,7 @@ // Purpose: Defines wxTaskBarIcon class for manipulating icons on the // Windows task bar. // Author: Julian Smart -// Modified by: +// Modified by: Vaclav Slavik // Created: 24/3/98 // RCS-ID: $Id$ // Copyright: (c) Julian Smart @@ -17,24 +17,20 @@ #pragma interface "taskbar.h" #endif -#include "wx/list.h" #include "wx/icon.h" -class WXDLLIMPEXP_ADV wxTaskBarIcon; - -WX_DECLARE_LIST_WITH_DECL(wxTaskBarIcon, wxTaskBarIconList, - class WXDLLIMPEXP_ADV); +// private helper class: +class WXDLLIMPEXP_ADV wxTaskBarIconWindow; class WXDLLIMPEXP_ADV wxTaskBarIcon: public wxTaskBarIconBase { DECLARE_DYNAMIC_CLASS_NO_COPY(wxTaskBarIcon) public: - wxTaskBarIcon(void); - virtual ~wxTaskBarIcon(void); + wxTaskBarIcon(); + virtual ~wxTaskBarIcon(); // Accessors - inline WXHWND GetHWND() const { return m_hWnd; } - inline bool IsOk() const { return (m_hWnd != 0) ; } + inline bool IsOk() const { return true; } inline bool IsIconInstalled() const { return m_iconAdded; } // Operations @@ -56,21 +52,18 @@ public: #endif // Implementation - static wxTaskBarIcon* FindObjectForHWND(WXHWND hWnd); - static void AddObject(wxTaskBarIcon* obj); - static void RemoveObject(wxTaskBarIcon* obj); - static bool RegisterWindowClass(); - static WXHWND CreateTaskBarWindow(); - long WindowProc( WXHWND hWnd, unsigned int msg, unsigned int wParam, long lParam ); +protected: + friend class wxTaskBarIconWindow; + long WindowProc(WXHWND hWnd, unsigned int msg, + unsigned int wParam, long lParam); + void RegisterWindowMessages(); // Data members protected: - WXHWND m_hWnd; - bool m_iconAdded; - wxIcon m_icon; - wxString m_strTooltip; - - static wxTaskBarIconList sm_taskBarIcons; + wxTaskBarIconWindow *m_win; + bool m_iconAdded; + wxIcon m_icon; + wxString m_strTooltip; #if WXWIN_COMPATIBILITY_2_4 // non-virtual default event handlers to forward events to the virtuals @@ -92,8 +85,3 @@ inline bool wxTaskBarIcon::IsOK() const { return IsOk(); } #endif // _TASKBAR_H_ - - - - - diff --git a/samples/taskbar/tbtest.cpp b/samples/taskbar/tbtest.cpp index c989143edc..240abe59ff 100644 --- a/samples/taskbar/tbtest.cpp +++ b/samples/taskbar/tbtest.cpp @@ -22,7 +22,7 @@ // the application icon (under Windows and OS/2 it is in resources) #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) || defined(__WXX11__) - #include "mondrian.xpm" + #include "../sample.xpm" #endif #include "wx/taskbar.h" @@ -35,9 +35,6 @@ IMPLEMENT_APP(MyApp) bool MyApp::OnInit(void) { - if (!m_taskBarIcon.SetIcon(wxICON(mondrian), wxT("wxTaskBarIcon Sample"))) - wxMessageBox(wxT("Could not set icon.")); - // Create the main frame window dialog = new MyDialog(NULL, -1, wxT("wxTaskBarIcon Test Dialog"), wxPoint(-1, -1), wxSize(365, 290), wxDIALOG_MODELESS|wxDEFAULT_DIALOG_STYLE); @@ -62,6 +59,11 @@ MyDialog::MyDialog(wxWindow* parent, const wxWindowID id, const wxString& title, Init(); } +MyDialog::~MyDialog() +{ + delete m_taskBarIcon; +} + void MyDialog::OnOK(wxCommandEvent& WXUNUSED(event)) { Show(FALSE); @@ -88,6 +90,11 @@ void MyDialog::Init(void) (void)new wxButton(this, wxID_EXIT, _T("Exit"), wxPoint(185, 230), wxSize(80, 25)); (new wxButton(this, wxID_OK, _T("OK"), wxPoint(100, 230), wxSize(80, 25)))->SetDefault(); Centre(wxBOTH); + + + m_taskBarIcon = new MyTaskBarIcon(); + if (!m_taskBarIcon->SetIcon(wxICON(sample), wxT("wxTaskBarIcon Sample"))) + wxMessageBox(wxT("Could not set icon.")); } diff --git a/samples/taskbar/tbtest.h b/samples/taskbar/tbtest.h index a3ce1b2940..24ab1de7c8 100644 --- a/samples/taskbar/tbtest.h +++ b/samples/taskbar/tbtest.h @@ -29,8 +29,6 @@ class MyApp: public wxApp { public: bool OnInit(void); -protected: - MyTaskBarIcon m_taskBarIcon; }; class MyDialog: public wxDialog @@ -38,12 +36,16 @@ class MyDialog: public wxDialog public: MyDialog(wxWindow* parent, const wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, const long windowStyle = wxDEFAULT_DIALOG_STYLE); + ~MyDialog(); void OnOK(wxCommandEvent& event); void OnExit(wxCommandEvent& event); void OnCloseWindow(wxCloseEvent& event); void Init(void); +protected: + MyTaskBarIcon *m_taskBarIcon; + DECLARE_EVENT_TABLE() }; diff --git a/src/msw/taskbar.cpp b/src/msw/taskbar.cpp index 90bb7742c7..f6512bba8b 100644 --- a/src/msw/taskbar.cpp +++ b/src/msw/taskbar.cpp @@ -3,7 +3,7 @@ // Purpose: Implements wxTaskBarIcon class for manipulating icons on // the Windows task bar. // Author: Julian Smart -// Modified by: +// Modified by: Vaclav Slavik // Created: 24/3/98 // RCS-ID: $Id$ // Copyright: (c) @@ -46,16 +46,6 @@ #include #endif -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxTaskBarIconList); - -LRESULT APIENTRY _EXPORT -wxTaskBarIconWindowProc( HWND hWnd, unsigned msg, UINT wParam, LONG lParam ); - -wxChar *wxTaskBarWindowClass = (wxChar*) wxT("wxTaskBarWindowClass"); - -wxTaskBarIconList wxTaskBarIcon::sm_taskBarIcons; - // initialized on demand UINT gs_msgTaskbar = 0; UINT gs_msgRestartTaskbar = 0; @@ -79,6 +69,41 @@ IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler) // implementation // ============================================================================ +// ---------------------------------------------------------------------------- +// wxTaskBarIconWindow: helper window +// ---------------------------------------------------------------------------- + +// NB: this class serves two purposes: +// 1. win32 needs a HWND associated with taskbar icon, this provides it +// 2. we need wxTopLevelWindow so that the app doesn't exit when +// last frame is closed but there still is a taskbar icon +class wxTaskBarIconWindow : public wxFrame +{ +public: + wxTaskBarIconWindow(wxTaskBarIcon *icon) + : wxFrame(NULL, -1, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0), + m_icon(icon) + { + } + + WXLRESULT MSWWindowProc(WXUINT msg, + WXWPARAM wParam, WXLPARAM lParam) + { + if (msg == gs_msgRestartTaskbar || msg == gs_msgTaskbar) + { + return m_icon->WindowProc(GetHWND(), msg, wParam, lParam); + } + else + { + return wxFrame::MSWWindowProc(msg, wParam, lParam); + } + } + +private: + wxTaskBarIcon *m_icon; +}; + + // ---------------------------------------------------------------------------- // NotifyIconData: wrapper around NOTIFYICONDATA // ---------------------------------------------------------------------------- @@ -105,41 +130,35 @@ struct NotifyIconData : public NOTIFYICONDATA wxTaskBarIcon::wxTaskBarIcon() { - m_hWnd = 0; + m_win = NULL; m_iconAdded = false; - - AddObject(this); - - if (RegisterWindowClass()) - m_hWnd = CreateTaskBarWindow(); + RegisterWindowMessages(); } wxTaskBarIcon::~wxTaskBarIcon() { - RemoveObject(this); - if (m_iconAdded) - { RemoveIcon(); - } - if (m_hWnd) - { - ::DestroyWindow((HWND) m_hWnd); - m_hWnd = 0; - } + if (m_win) + m_win->Destroy(); } // Operations bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip) { - if (!IsOk()) - return false; + // NB: we have to create the window lazily because of backward compatiblity, + // old aplications may create wxTaskBarIcon instance before wxApp + // is initialized (as samples/taskbar used to do) + if (!m_win) + { + m_win = new wxTaskBarIconWindow(this); + } m_icon = icon; m_strTooltip = tooltip; - NotifyIconData notifyData(m_hWnd); + NotifyIconData notifyData((HWND)m_win->GetHWND()); if (icon.Ok()) { @@ -170,13 +189,15 @@ bool wxTaskBarIcon::RemoveIcon() m_iconAdded = false; - NotifyIconData notifyData(m_hWnd); + NotifyIconData notifyData((HWND)m_win->GetHWND()); return Shell_NotifyIcon(NIM_DELETE, ¬ifyData) != 0; } bool wxTaskBarIcon::PopupMenu(wxMenu *menu) { + wxASSERT_MSG( m_win != NULL, _T("taskbar icon not initialized") ); + static bool s_inPopup = false; if (s_inPopup) @@ -184,31 +205,24 @@ bool wxTaskBarIcon::PopupMenu(wxMenu *menu) s_inPopup = true; - wxWindow* win; int x, y; wxGetMousePosition(&x, &y); - // is wxFrame the best window type to use??? - win = new wxFrame(NULL, -1, wxEmptyString, wxPoint(x,y), wxSize(-1,-1), 0); - win->PushEventHandler(this); - - // Remove from record of top-level windows, or will confuse wxWindows - // if we try to exit right now. - wxTopLevelWindows.DeleteObject(win); + m_win->Move(x, y); + + m_win->PushEventHandler(this); menu->UpdateUI(); // Work around a WIN32 bug - ::SetForegroundWindow ((HWND) win->GetHWND ()); + ::SetForegroundWindow((HWND)m_win->GetHWND()); - bool rval = win->PopupMenu(menu, 0, 0); + bool rval = m_win->PopupMenu(menu, 0, 0); // Work around a WIN32 bug - ::PostMessage ((HWND) win->GetHWND(),WM_NULL,0,0L); + ::PostMessage((HWND)m_win->GetHWND(), WM_NULL, 0, 0L); - win->PopEventHandler(false); - win->Destroy(); - delete win; + m_win->PopEventHandler(false); s_inPopup = false; @@ -234,84 +248,20 @@ void wxTaskBarIcon::_OnLButtonDClick(wxEvent& e) { OnLButtonDClick(e); } void wxTaskBarIcon::_OnRButtonDClick(wxEvent& e) { OnRButtonDClick(e); } #endif -wxTaskBarIcon* wxTaskBarIcon::FindObjectForHWND(WXHWND hWnd) -{ - wxTaskBarIconList::compatibility_iterator node = sm_taskBarIcons.GetFirst(); - while (node) - { - wxTaskBarIcon *obj = node->GetData(); - if (obj->GetHWND() == hWnd) - return obj; - node = node->GetNext(); - } - return NULL; -} - -void wxTaskBarIcon::AddObject(wxTaskBarIcon* obj) -{ - sm_taskBarIcons.Append(obj); -} - -void wxTaskBarIcon::RemoveObject(wxTaskBarIcon* obj) -{ - sm_taskBarIcons.DeleteObject(obj); -} - -bool wxTaskBarIcon::RegisterWindowClass() +void wxTaskBarIcon::RegisterWindowMessages() { static bool s_registered = false; - if ( s_registered ) - return true; - - // Taskbar restart msg will be sent to us if the icon needs to be redrawn - gs_msgRestartTaskbar = RegisterWindowMessage(wxT("TaskbarCreated")); - - // Also register the taskbar message here - gs_msgTaskbar = ::RegisterWindowMessage(wxT("wxTaskBarIconMessage")); - - // set up and register window class - WNDCLASS wc; - wc.style = CS_HREDRAW | CS_VREDRAW; - wc.lpfnWndProc = (WNDPROC) wxTaskBarIconWindowProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = wxGetInstance(); - wc.hIcon = 0; - wc.hCursor = 0; - wc.hbrBackground = 0; - wc.lpszMenuName = NULL; - wc.lpszClassName = wxTaskBarWindowClass; - - if ( !::RegisterClass(&wc) ) - { - wxLogLastError(_T("RegisterClass(taskbar icon)")); - - return false; - } - - s_registered = true; + if ( !s_registered ) + { + // Taskbar restart msg will be sent to us if the icon needs to be redrawn + gs_msgRestartTaskbar = RegisterWindowMessage(wxT("TaskbarCreated")); - return true; -} + // Also register the taskbar message here + gs_msgTaskbar = ::RegisterWindowMessage(wxT("wxTaskBarIconMessage")); -WXHWND wxTaskBarIcon::CreateTaskBarWindow() -{ - HINSTANCE hInstance = wxGetInstance(); - - HWND hWnd = CreateWindowEx (0, wxTaskBarWindowClass, - wxT("wxTaskBarWindow"), - WS_OVERLAPPED, - 0, - 0, - 10, - 10, - NULL, - (HMENU) 0, - hInstance, - NULL); - - return (WXHWND) hWnd; + s_registered = true; + } } // ---------------------------------------------------------------------------- @@ -331,8 +281,8 @@ long wxTaskBarIcon::WindowProc(WXHWND hWnd, SetIcon(m_icon, m_strTooltip); } - if (msg != gs_msgTaskbar) - return DefWindowProc((HWND) hWnd, msg, wParam, lParam); + // this function should only be called for gs_msg(Restart)Taskbar messages + wxASSERT(msg == gs_msgTaskbar); switch (lParam) { @@ -378,15 +328,4 @@ long wxTaskBarIcon::WindowProc(WXHWND hWnd, return 0; } -LRESULT APIENTRY _EXPORT -wxTaskBarIconWindowProc(HWND hWnd, unsigned msg, UINT wParam, LONG lParam) -{ - wxTaskBarIcon *obj = wxTaskBarIcon::FindObjectForHWND((WXHWND) hWnd); - if (obj) - return obj->WindowProc((WXHWND) hWnd, msg, wParam, lParam); - else - return DefWindowProc(hWnd, msg, wParam, lParam); -} - -#endif - // __WIN95__ +#endif // __WIN95__