Use a single taskbar icon for all notifications in wxMSW.

Allocating a new icon for every notification could result in showing many
identical icons in the taskbar notification area if several notification
messages were generated which looked like a bug to the user. It was also
inconsistent with the behaviour in the case when UseTaskBarIcon() was called.

Always behave as in the latter case now, i.e. any subsequent notification
replaces the previous one instead of being shown in addition to it.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@73287 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2012-12-28 16:02:04 +00:00
parent 0a890608f1
commit 3b4b952d42

View File

@@ -92,9 +92,10 @@ private:
class wxBalloonNotifMsgImpl : public wxNotifMsgImpl class wxBalloonNotifMsgImpl : public wxNotifMsgImpl
{ {
public: public:
// ctor sets up m_icon (using the icon of the top level parent of the given // Ctor creates the associated taskbar icon (using the icon of the top
// window) which can be used to show an attached balloon later by the // level parent of the given window) unless UseTaskBarIcon() had been
// derived classes // previously called which can be used to show an attached balloon later
// by the derived classes.
wxBalloonNotifMsgImpl(wxWindow *win) { SetUpIcon(win); } wxBalloonNotifMsgImpl(wxWindow *win) { SetUpIcon(win); }
// implementation of wxNotificationMessage method with the same name // implementation of wxNotificationMessage method with the same name
@@ -105,20 +106,53 @@ public:
int timeout, int timeout,
int flags); int flags);
// Returns true if we're using our own icon or false if we're hitching a
// ride on the application icon provided to us via UseTaskBarIcon().
static bool IsUsingOwnIcon()
{
return ms_refCountIcon != -1;
}
// Indicates that the taskbar icon we're using has been hidden and can be
// deleted.
//
// This is only called by wxNotificationIconEvtHandler and should only be
// called when using our own icon (as opposed to the one passed to us via
// UseTaskBarIcon()).
static void ReleaseIcon()
{
wxASSERT_MSG( ms_refCountIcon != -1,
wxS("Must not be called when not using own icon") );
if ( !--ms_refCountIcon )
{
delete ms_icon;
ms_icon = NULL;
}
}
protected: protected:
// sets up m_icon (doesn't do anything with the old value, caller beware) // Creates a new icon if necessary, see the comment below.
void SetUpIcon(wxWindow *win); void SetUpIcon(wxWindow *win);
static wxTaskBarIcon *ms_iconToUse; // We need an icon to show the notification in a balloon attached to it.
// It may happen that the main application already shows an icon in the
// the icon we attach our notification to, either ms_iconToUse or a // taskbar notification area in which case it should call our
// temporary one which we will destroy when done // UseTaskBarIcon() and we just use this icon without ever allocating nor
wxTaskBarIcon *m_icon; // deleting it and ms_refCountIcon is -1 and never changes. Otherwise, we
// create the icon when we need it the first time but reuse it if we need
// should be only used if m_icon != NULL and indicates whether we should // to show subsequent notifications while this icon is still alive. This is
// delete it // needed in order to avoid 2 or 3 or even more identical icons if a couple
bool m_ownsIcon; // of notifications are shown in a row (which happens quite easily in
// practice because Windows helpfully buffers all the notifications that
// were generated while the user was away -- i.e. the screensaver was
// active -- and then shows them all at once when the user comes back). In
// this case, ms_refCountIcon is used as a normal reference counter, i.e.
// the icon is only destroyed when it reaches 0.
static wxTaskBarIcon *ms_icon;
static int ms_refCountIcon;
}; };
// implementation for automatically hidden notifications // implementation for automatically hidden notifications
@@ -212,7 +246,7 @@ wxNotificationIconEvtHandler::wxNotificationIconEvtHandler(wxTaskBarIcon *icon)
void wxNotificationIconEvtHandler::OnIconHidden() void wxNotificationIconEvtHandler::OnIconHidden()
{ {
delete m_icon; wxBalloonNotifMsgImpl::ReleaseIcon();
delete this; delete this;
} }
@@ -234,29 +268,36 @@ void wxNotificationIconEvtHandler::OnClick(wxTaskBarIconEvent& WXUNUSED(event))
// wxBalloonNotifMsgImpl // wxBalloonNotifMsgImpl
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
wxTaskBarIcon *wxBalloonNotifMsgImpl::ms_iconToUse = NULL; wxTaskBarIcon *wxBalloonNotifMsgImpl::ms_icon = NULL;
int wxBalloonNotifMsgImpl::ms_refCountIcon = 0;
/* static */ /* static */
wxTaskBarIcon *wxBalloonNotifMsgImpl::UseTaskBarIcon(wxTaskBarIcon *icon) wxTaskBarIcon *wxBalloonNotifMsgImpl::UseTaskBarIcon(wxTaskBarIcon *icon)
{ {
wxTaskBarIcon * const iconOld = ms_iconToUse; wxTaskBarIcon * const iconOld = ms_icon;
ms_iconToUse = icon; ms_icon = icon;
// Don't use reference counting for the provided icon, we don't own it.
ms_refCountIcon = icon ? -1 : 0;
return iconOld; return iconOld;
} }
void wxBalloonNotifMsgImpl::SetUpIcon(wxWindow *win) void wxBalloonNotifMsgImpl::SetUpIcon(wxWindow *win)
{ {
if ( ms_iconToUse ) if ( ms_icon )
{ {
// use an existing icon // Increment the reference count if we manage the icon on our own.
m_ownsIcon = false; if ( ms_refCountIcon != -1 )
m_icon = ms_iconToUse; ms_refCountIcon++;
} }
else // no user-specified icon to attach to else // Create a new icon.
{ {
// create our own one wxASSERT_MSG( ms_refCountIcon == 0,
m_ownsIcon = true; wxS("Shouldn't reference not existent icon") );
m_icon = new wxTaskBarIcon;
ms_icon = new wxTaskBarIcon;
ms_refCountIcon = 1;
// use the icon of the associated (or main, if none) frame // use the icon of the associated (or main, if none) frame
wxIcon icon; wxIcon icon;
@@ -278,7 +319,7 @@ void wxBalloonNotifMsgImpl::SetUpIcon(wxWindow *win)
icon = wxIcon(wxT("wxICON_AAA")); icon = wxIcon(wxT("wxICON_AAA"));
} }
m_icon->SetIcon(icon); ms_icon->SetIcon(icon);
} }
} }
@@ -288,7 +329,7 @@ wxBalloonNotifMsgImpl::DoShow(const wxString& title,
int timeout, int timeout,
int flags) int flags)
{ {
if ( !m_icon->IsIconInstalled() ) if ( !ms_icon->IsIconInstalled() )
{ {
// If we failed to install the icon (which does happen sometimes, // If we failed to install the icon (which does happen sometimes,
// although only in unusual circumstances, e.g. it happens regularly, // although only in unusual circumstances, e.g. it happens regularly,
@@ -299,15 +340,15 @@ wxBalloonNotifMsgImpl::DoShow(const wxString& title,
// forever because we're not going to receive a notification about icon // forever because we're not going to receive a notification about icon
// disappearance from the system if we failed to install it in the // disappearance from the system if we failed to install it in the
// first place. // first place.
delete m_icon; delete ms_icon;
m_icon = NULL; ms_icon = NULL;
return false; return false;
} }
timeout *= 1000; // Windows expresses timeout in milliseconds timeout *= 1000; // Windows expresses timeout in milliseconds
return m_icon->ShowBalloon(title, message, timeout, flags); return ms_icon->ShowBalloon(title, message, timeout, flags);
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -322,7 +363,7 @@ wxManualNotifMsgImpl::wxManualNotifMsgImpl(wxWindow *win)
wxManualNotifMsgImpl::~wxManualNotifMsgImpl() wxManualNotifMsgImpl::~wxManualNotifMsgImpl()
{ {
if ( m_icon ) if ( ms_icon )
DoClose(); DoClose();
} }
@@ -337,7 +378,7 @@ wxManualNotifMsgImpl::DoShow(const wxString& title,
// base class creates the icon for us initially but we could have destroyed // base class creates the icon for us initially but we could have destroyed
// it in DoClose(), recreate it if this was the case // it in DoClose(), recreate it if this was the case
if ( !m_icon ) if ( !ms_icon )
SetUpIcon(m_win); SetUpIcon(m_win);
// use maximal (in current Windows versions) timeout (but it will still // use maximal (in current Windows versions) timeout (but it will still
@@ -347,19 +388,17 @@ wxManualNotifMsgImpl::DoShow(const wxString& title,
bool wxManualNotifMsgImpl::DoClose() bool wxManualNotifMsgImpl::DoClose()
{ {
if ( m_ownsIcon ) if ( IsUsingOwnIcon() )
{ {
// we don't need the icon any more // we don't need the icon any more
delete m_icon; ReleaseIcon();
} }
else // using an existing icon else // using an existing icon
{ {
// just hide the balloon // just hide the balloon
m_icon->ShowBalloon("", ""); ms_icon->ShowBalloon("", "");
} }
m_icon = NULL;
return true; return true;
} }
@@ -370,11 +409,11 @@ bool wxManualNotifMsgImpl::DoClose()
wxAutoNotifMsgImpl::wxAutoNotifMsgImpl(wxWindow *win) wxAutoNotifMsgImpl::wxAutoNotifMsgImpl(wxWindow *win)
: wxBalloonNotifMsgImpl(win) : wxBalloonNotifMsgImpl(win)
{ {
if ( m_ownsIcon ) if ( ms_refCountIcon != -1 )
{ {
// This object will self-destruct and also delete the icon when the // This object will self-destruct and decrease the ref count of the
// notification is hidden. // icon when the notification is hidden.
new wxNotificationIconEvtHandler(m_icon); new wxNotificationIconEvtHandler(ms_icon);
} }
} }