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
This commit is contained in:
Václav Slavík
2004-03-23 23:20:16 +00:00
parent 814e9c24c2
commit 1e6d9c20fd
5 changed files with 107 additions and 163 deletions

View File

@@ -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 - 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 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 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 DEPRECATED METHODS SINCE 2.4.x
@@ -92,6 +98,8 @@ wxMSW:
- wxMenuBar::GetLabelTop() doesn't include '&'s in the label any more - wxMenuBar::GetLabelTop() doesn't include '&'s in the label any more
- wxRegConf couldn't read global settings without admin privileges and didn't - wxRegConf couldn't read global settings without admin privileges and didn't
even try to do it by default -- now it does 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: wxMotif:

View File

@@ -3,7 +3,7 @@
// Purpose: Defines wxTaskBarIcon class for manipulating icons on the // Purpose: Defines wxTaskBarIcon class for manipulating icons on the
// Windows task bar. // Windows task bar.
// Author: Julian Smart // Author: Julian Smart
// Modified by: // Modified by: Vaclav Slavik
// Created: 24/3/98 // Created: 24/3/98
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) Julian Smart // Copyright: (c) Julian Smart
@@ -17,24 +17,20 @@
#pragma interface "taskbar.h" #pragma interface "taskbar.h"
#endif #endif
#include "wx/list.h"
#include "wx/icon.h" #include "wx/icon.h"
class WXDLLIMPEXP_ADV wxTaskBarIcon; // private helper class:
class WXDLLIMPEXP_ADV wxTaskBarIconWindow;
WX_DECLARE_LIST_WITH_DECL(wxTaskBarIcon, wxTaskBarIconList,
class WXDLLIMPEXP_ADV);
class WXDLLIMPEXP_ADV wxTaskBarIcon: public wxTaskBarIconBase class WXDLLIMPEXP_ADV wxTaskBarIcon: public wxTaskBarIconBase
{ {
DECLARE_DYNAMIC_CLASS_NO_COPY(wxTaskBarIcon) DECLARE_DYNAMIC_CLASS_NO_COPY(wxTaskBarIcon)
public: public:
wxTaskBarIcon(void); wxTaskBarIcon();
virtual ~wxTaskBarIcon(void); virtual ~wxTaskBarIcon();
// Accessors // Accessors
inline WXHWND GetHWND() const { return m_hWnd; } inline bool IsOk() const { return true; }
inline bool IsOk() const { return (m_hWnd != 0) ; }
inline bool IsIconInstalled() const { return m_iconAdded; } inline bool IsIconInstalled() const { return m_iconAdded; }
// Operations // Operations
@@ -56,21 +52,18 @@ public:
#endif #endif
// Implementation // Implementation
static wxTaskBarIcon* FindObjectForHWND(WXHWND hWnd); protected:
static void AddObject(wxTaskBarIcon* obj); friend class wxTaskBarIconWindow;
static void RemoveObject(wxTaskBarIcon* obj); long WindowProc(WXHWND hWnd, unsigned int msg,
static bool RegisterWindowClass(); unsigned int wParam, long lParam);
static WXHWND CreateTaskBarWindow(); void RegisterWindowMessages();
long WindowProc( WXHWND hWnd, unsigned int msg, unsigned int wParam, long lParam );
// Data members // Data members
protected: protected:
WXHWND m_hWnd; wxTaskBarIconWindow *m_win;
bool m_iconAdded; bool m_iconAdded;
wxIcon m_icon; wxIcon m_icon;
wxString m_strTooltip; wxString m_strTooltip;
static wxTaskBarIconList sm_taskBarIcons;
#if WXWIN_COMPATIBILITY_2_4 #if WXWIN_COMPATIBILITY_2_4
// non-virtual default event handlers to forward events to the virtuals // non-virtual default event handlers to forward events to the virtuals
@@ -92,8 +85,3 @@ inline bool wxTaskBarIcon::IsOK() const { return IsOk(); }
#endif #endif
// _TASKBAR_H_ // _TASKBAR_H_

View File

@@ -22,7 +22,7 @@
// the application icon (under Windows and OS/2 it is in resources) // the application icon (under Windows and OS/2 it is in resources)
#if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) || defined(__WXX11__) #if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXMAC__) || defined(__WXMGL__) || defined(__WXX11__)
#include "mondrian.xpm" #include "../sample.xpm"
#endif #endif
#include "wx/taskbar.h" #include "wx/taskbar.h"
@@ -35,9 +35,6 @@ IMPLEMENT_APP(MyApp)
bool MyApp::OnInit(void) bool MyApp::OnInit(void)
{ {
if (!m_taskBarIcon.SetIcon(wxICON(mondrian), wxT("wxTaskBarIcon Sample")))
wxMessageBox(wxT("Could not set icon."));
// Create the main frame window // 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); 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(); Init();
} }
MyDialog::~MyDialog()
{
delete m_taskBarIcon;
}
void MyDialog::OnOK(wxCommandEvent& WXUNUSED(event)) void MyDialog::OnOK(wxCommandEvent& WXUNUSED(event))
{ {
Show(FALSE); Show(FALSE);
@@ -88,6 +90,11 @@ void MyDialog::Init(void)
(void)new wxButton(this, wxID_EXIT, _T("Exit"), wxPoint(185, 230), wxSize(80, 25)); (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(); (new wxButton(this, wxID_OK, _T("OK"), wxPoint(100, 230), wxSize(80, 25)))->SetDefault();
Centre(wxBOTH); Centre(wxBOTH);
m_taskBarIcon = new MyTaskBarIcon();
if (!m_taskBarIcon->SetIcon(wxICON(sample), wxT("wxTaskBarIcon Sample")))
wxMessageBox(wxT("Could not set icon."));
} }

View File

@@ -29,8 +29,6 @@ class MyApp: public wxApp
{ {
public: public:
bool OnInit(void); bool OnInit(void);
protected:
MyTaskBarIcon m_taskBarIcon;
}; };
class MyDialog: public wxDialog class MyDialog: public wxDialog
@@ -38,12 +36,16 @@ class MyDialog: public wxDialog
public: public:
MyDialog(wxWindow* parent, const wxWindowID id, const wxString& title, MyDialog(wxWindow* parent, const wxWindowID id, const wxString& title,
const wxPoint& pos, const wxSize& size, const long windowStyle = wxDEFAULT_DIALOG_STYLE); const wxPoint& pos, const wxSize& size, const long windowStyle = wxDEFAULT_DIALOG_STYLE);
~MyDialog();
void OnOK(wxCommandEvent& event); void OnOK(wxCommandEvent& event);
void OnExit(wxCommandEvent& event); void OnExit(wxCommandEvent& event);
void OnCloseWindow(wxCloseEvent& event); void OnCloseWindow(wxCloseEvent& event);
void Init(void); void Init(void);
protected:
MyTaskBarIcon *m_taskBarIcon;
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
}; };

View File

@@ -3,7 +3,7 @@
// Purpose: Implements wxTaskBarIcon class for manipulating icons on // Purpose: Implements wxTaskBarIcon class for manipulating icons on
// the Windows task bar. // the Windows task bar.
// Author: Julian Smart // Author: Julian Smart
// Modified by: // Modified by: Vaclav Slavik
// Created: 24/3/98 // Created: 24/3/98
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) // Copyright: (c)
@@ -46,16 +46,6 @@
#include <shellapi.h> #include <shellapi.h>
#endif #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 // initialized on demand
UINT gs_msgTaskbar = 0; UINT gs_msgTaskbar = 0;
UINT gs_msgRestartTaskbar = 0; UINT gs_msgRestartTaskbar = 0;
@@ -79,6 +69,41 @@ IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler)
// implementation // 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 // NotifyIconData: wrapper around NOTIFYICONDATA
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -105,41 +130,35 @@ struct NotifyIconData : public NOTIFYICONDATA
wxTaskBarIcon::wxTaskBarIcon() wxTaskBarIcon::wxTaskBarIcon()
{ {
m_hWnd = 0; m_win = NULL;
m_iconAdded = false; m_iconAdded = false;
RegisterWindowMessages();
AddObject(this);
if (RegisterWindowClass())
m_hWnd = CreateTaskBarWindow();
} }
wxTaskBarIcon::~wxTaskBarIcon() wxTaskBarIcon::~wxTaskBarIcon()
{ {
RemoveObject(this);
if (m_iconAdded) if (m_iconAdded)
{
RemoveIcon(); RemoveIcon();
}
if (m_hWnd) if (m_win)
{ m_win->Destroy();
::DestroyWindow((HWND) m_hWnd);
m_hWnd = 0;
}
} }
// Operations // Operations
bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip) bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
{ {
if (!IsOk()) // NB: we have to create the window lazily because of backward compatiblity,
return false; // 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_icon = icon;
m_strTooltip = tooltip; m_strTooltip = tooltip;
NotifyIconData notifyData(m_hWnd); NotifyIconData notifyData((HWND)m_win->GetHWND());
if (icon.Ok()) if (icon.Ok())
{ {
@@ -170,13 +189,15 @@ bool wxTaskBarIcon::RemoveIcon()
m_iconAdded = false; m_iconAdded = false;
NotifyIconData notifyData(m_hWnd); NotifyIconData notifyData((HWND)m_win->GetHWND());
return Shell_NotifyIcon(NIM_DELETE, &notifyData) != 0; return Shell_NotifyIcon(NIM_DELETE, &notifyData) != 0;
} }
bool wxTaskBarIcon::PopupMenu(wxMenu *menu) bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
{ {
wxASSERT_MSG( m_win != NULL, _T("taskbar icon not initialized") );
static bool s_inPopup = false; static bool s_inPopup = false;
if (s_inPopup) if (s_inPopup)
@@ -184,31 +205,24 @@ bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
s_inPopup = true; s_inPopup = true;
wxWindow* win;
int x, y; int x, y;
wxGetMousePosition(&x, &y); wxGetMousePosition(&x, &y);
// is wxFrame the best window type to use??? m_win->Move(x, y);
win = new wxFrame(NULL, -1, wxEmptyString, wxPoint(x,y), wxSize(-1,-1), 0);
win->PushEventHandler(this); m_win->PushEventHandler(this);
// Remove from record of top-level windows, or will confuse wxWindows
// if we try to exit right now.
wxTopLevelWindows.DeleteObject(win);
menu->UpdateUI(); menu->UpdateUI();
// Work around a WIN32 bug // 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 // 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); m_win->PopEventHandler(false);
win->Destroy();
delete win;
s_inPopup = false; s_inPopup = false;
@@ -234,84 +248,20 @@ void wxTaskBarIcon::_OnLButtonDClick(wxEvent& e) { OnLButtonDClick(e); }
void wxTaskBarIcon::_OnRButtonDClick(wxEvent& e) { OnRButtonDClick(e); } void wxTaskBarIcon::_OnRButtonDClick(wxEvent& e) { OnRButtonDClick(e); }
#endif #endif
wxTaskBarIcon* wxTaskBarIcon::FindObjectForHWND(WXHWND hWnd) void wxTaskBarIcon::RegisterWindowMessages()
{
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()
{ {
static bool s_registered = false; static bool s_registered = false;
if ( s_registered ) 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"));
// Taskbar restart msg will be sent to us if the icon needs to be redrawn // Also register the taskbar message here
gs_msgRestartTaskbar = RegisterWindowMessage(wxT("TaskbarCreated")); gs_msgTaskbar = ::RegisterWindowMessage(wxT("wxTaskBarIconMessage"));
// Also register the taskbar message here s_registered = true;
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;
return true;
}
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;
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -331,8 +281,8 @@ long wxTaskBarIcon::WindowProc(WXHWND hWnd,
SetIcon(m_icon, m_strTooltip); SetIcon(m_icon, m_strTooltip);
} }
if (msg != gs_msgTaskbar) // this function should only be called for gs_msg(Restart)Taskbar messages
return DefWindowProc((HWND) hWnd, msg, wParam, lParam); wxASSERT(msg == gs_msgTaskbar);
switch (lParam) switch (lParam)
{ {
@@ -378,15 +328,4 @@ long wxTaskBarIcon::WindowProc(WXHWND hWnd,
return 0; return 0;
} }
LRESULT APIENTRY _EXPORT #endif // __WIN95__
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__