1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/notifmsg.cpp
3 // Purpose: implementation of wxNotificationMessage for Windows
4 // Author: Vadim Zeitlin
6 // Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
10 // ============================================================================
12 // ============================================================================
14 // ----------------------------------------------------------------------------
16 // ----------------------------------------------------------------------------
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
25 // we can only use the native implementation if we have a working
26 // wxTaskBarIcon::ShowBalloon() method
27 #if wxUSE_NOTIFICATION_MESSAGE && \
28 wxUSE_TASKBARICON && wxUSE_TASKBARICON_BALLOONS
30 #include "wx/notifmsg.h"
33 #include "wx/toplevel.h"
35 #include "wx/string.h"
38 #include "wx/generic/notifmsg.h"
40 #include "wx/taskbar.h"
42 // ----------------------------------------------------------------------------
43 // different implementations used by wxNotificationMessage
44 // ----------------------------------------------------------------------------
46 // base class for all available implementations
51 virtual ~wxNotifMsgImpl() { }
53 virtual bool DoShow(const wxString
& title
,
54 const wxString
& message
,
57 virtual bool DoClose() = 0;
60 wxDECLARE_NO_COPY_CLASS(wxNotifMsgImpl
);
63 // implementation which is simply a bridge to wxGenericNotificationMessage
64 class wxGenericNotifMsgImpl
: public wxNotifMsgImpl
67 wxGenericNotifMsgImpl() : m_notif(new wxGenericNotificationMessage
) { }
68 virtual ~wxGenericNotifMsgImpl() { delete m_notif
; }
70 virtual bool DoShow(const wxString
& title
,
71 const wxString
& message
,
75 m_notif
->SetTitle(title
);
76 m_notif
->SetMessage(message
);
77 m_notif
->SetFlags(flags
);
78 return m_notif
->Show(timeout
);
81 virtual bool DoClose()
83 return m_notif
->Close();
87 wxGenericNotificationMessage
* const m_notif
;
90 // common base class for implementations using a taskbar icon and balloons
91 class wxBalloonNotifMsgImpl
: public wxNotifMsgImpl
94 // Ctor creates the associated taskbar icon (using the icon of the top
95 // level parent of the given window) unless UseTaskBarIcon() had been
96 // previously called which can be used to show an attached balloon later
97 // by the derived classes.
98 wxBalloonNotifMsgImpl(wxWindow
*win
) { SetUpIcon(win
); }
100 // implementation of wxNotificationMessage method with the same name
101 static wxTaskBarIcon
*UseTaskBarIcon(wxTaskBarIcon
*icon
);
103 virtual bool DoShow(const wxString
& title
,
104 const wxString
& message
,
109 // Returns true if we're using our own icon or false if we're hitching a
110 // ride on the application icon provided to us via UseTaskBarIcon().
111 static bool IsUsingOwnIcon()
113 return ms_refCountIcon
!= -1;
116 // Indicates that the taskbar icon we're using has been hidden and can be
119 // This is only called by wxNotificationIconEvtHandler and should only be
120 // called when using our own icon (as opposed to the one passed to us via
121 // UseTaskBarIcon()).
122 static void ReleaseIcon()
124 wxASSERT_MSG( ms_refCountIcon
!= -1,
125 wxS("Must not be called when not using own icon") );
127 if ( !--ms_refCountIcon
)
135 // Creates a new icon if necessary, see the comment below.
136 void SetUpIcon(wxWindow
*win
);
139 // We need an icon to show the notification in a balloon attached to it.
140 // It may happen that the main application already shows an icon in the
141 // taskbar notification area in which case it should call our
142 // UseTaskBarIcon() and we just use this icon without ever allocating nor
143 // deleting it and ms_refCountIcon is -1 and never changes. Otherwise, we
144 // create the icon when we need it the first time but reuse it if we need
145 // to show subsequent notifications while this icon is still alive. This is
146 // needed in order to avoid 2 or 3 or even more identical icons if a couple
147 // of notifications are shown in a row (which happens quite easily in
148 // practice because Windows helpfully buffers all the notifications that
149 // were generated while the user was away -- i.e. the screensaver was
150 // active -- and then shows them all at once when the user comes back). In
151 // this case, ms_refCountIcon is used as a normal reference counter, i.e.
152 // the icon is only destroyed when it reaches 0.
153 static wxTaskBarIcon
*ms_icon
;
154 static int ms_refCountIcon
;
157 // implementation for automatically hidden notifications
158 class wxAutoNotifMsgImpl
: public wxBalloonNotifMsgImpl
161 wxAutoNotifMsgImpl(wxWindow
*win
);
163 virtual bool DoShow(const wxString
& title
,
164 const wxString
& message
,
168 // can't close automatic notification [currently]
169 virtual bool DoClose() { return false; }
172 // implementation for manually closed notifications
173 class wxManualNotifMsgImpl
: public wxBalloonNotifMsgImpl
176 wxManualNotifMsgImpl(wxWindow
*win
);
177 virtual ~wxManualNotifMsgImpl();
179 virtual bool DoShow(const wxString
& title
,
180 const wxString
& message
,
183 virtual bool DoClose();
186 // store ctor parameter as we need it to recreate the icon later if we're
187 // closed and shown again
188 wxWindow
* const m_win
;
191 // ----------------------------------------------------------------------------
192 // custom event handler for task bar icons
193 // ----------------------------------------------------------------------------
195 // normally we'd just use a custom taskbar icon class but this is impossible
196 // because we can be asked to attach the notifications to an existing icon
197 // which we didn't create, hence we install a special event handler allowing us
198 // to get the events we need (and, crucially, to delete the icon when it's not
199 // needed any more) in any case
201 class wxNotificationIconEvtHandler
: public wxEvtHandler
204 wxNotificationIconEvtHandler(wxTaskBarIcon
*icon
);
207 void OnTimeout(wxTaskBarIconEvent
& event
);
208 void OnClick(wxTaskBarIconEvent
& event
);
213 wxTaskBarIcon
* const m_icon
;
215 wxDECLARE_NO_COPY_CLASS(wxNotificationIconEvtHandler
);
218 // ============================================================================
220 // ============================================================================
222 // ----------------------------------------------------------------------------
223 // wxNotificationIconEvtHandler
224 // ----------------------------------------------------------------------------
226 wxNotificationIconEvtHandler::wxNotificationIconEvtHandler(wxTaskBarIcon
*icon
)
231 wxEVT_TASKBAR_BALLOON_TIMEOUT
,
232 wxTaskBarIconEventHandler(wxNotificationIconEvtHandler::OnTimeout
),
239 wxEVT_TASKBAR_BALLOON_CLICK
,
240 wxTaskBarIconEventHandler(wxNotificationIconEvtHandler::OnClick
),
246 void wxNotificationIconEvtHandler::OnIconHidden()
248 wxBalloonNotifMsgImpl::ReleaseIcon();
254 wxNotificationIconEvtHandler::OnTimeout(wxTaskBarIconEvent
& WXUNUSED(event
))
259 void wxNotificationIconEvtHandler::OnClick(wxTaskBarIconEvent
& WXUNUSED(event
))
261 // TODO: generate an event notifying the user code?
266 // ----------------------------------------------------------------------------
267 // wxBalloonNotifMsgImpl
268 // ----------------------------------------------------------------------------
270 wxTaskBarIcon
*wxBalloonNotifMsgImpl::ms_icon
= NULL
;
271 int wxBalloonNotifMsgImpl::ms_refCountIcon
= 0;
274 wxTaskBarIcon
*wxBalloonNotifMsgImpl::UseTaskBarIcon(wxTaskBarIcon
*icon
)
276 wxTaskBarIcon
* const iconOld
= ms_icon
;
279 // Don't use reference counting for the provided icon, we don't own it.
280 ms_refCountIcon
= icon
? -1 : 0;
285 void wxBalloonNotifMsgImpl::SetUpIcon(wxWindow
*win
)
289 // Increment the reference count if we manage the icon on our own.
290 if ( ms_refCountIcon
!= -1 )
293 else // Create a new icon.
295 wxASSERT_MSG( ms_refCountIcon
== 0,
296 wxS("Shouldn't reference not existent icon") );
298 ms_icon
= new wxTaskBarIcon
;
301 // use the icon of the associated (or main, if none) frame
304 win
= wxGetTopLevelParent(win
);
306 win
= wxTheApp
->GetTopWindow();
309 const wxTopLevelWindow
* const
310 tlw
= wxDynamicCast(win
, wxTopLevelWindow
);
312 icon
= tlw
->GetIcon();
317 // we really must have some icon
318 icon
= wxIcon(wxT("wxICON_AAA"));
321 ms_icon
->SetIcon(icon
);
326 wxBalloonNotifMsgImpl::DoShow(const wxString
& title
,
327 const wxString
& message
,
331 if ( !ms_icon
->IsIconInstalled() )
333 // If we failed to install the icon (which does happen sometimes,
334 // although only in unusual circumstances, e.g. it happens regularly,
335 // albeit not constantly, if we're used soon after resume from suspend
336 // under Windows 7), we should not call ShowBalloon() because it would
337 // just assert and return and we must delete the icon ourselves because
338 // otherwise its associated wxTaskBarIconWindow would remain alive
339 // forever because we're not going to receive a notification about icon
340 // disappearance from the system if we failed to install it in the
348 timeout
*= 1000; // Windows expresses timeout in milliseconds
350 return ms_icon
->ShowBalloon(title
, message
, timeout
, flags
);
353 // ----------------------------------------------------------------------------
354 // wxManualNotifMsgImpl
355 // ----------------------------------------------------------------------------
357 wxManualNotifMsgImpl::wxManualNotifMsgImpl(wxWindow
*win
)
358 : wxBalloonNotifMsgImpl(win
),
363 wxManualNotifMsgImpl::~wxManualNotifMsgImpl()
370 wxManualNotifMsgImpl::DoShow(const wxString
& title
,
371 const wxString
& message
,
372 int WXUNUSED_UNLESS_DEBUG(timeout
),
375 wxASSERT_MSG( timeout
== wxNotificationMessage::Timeout_Never
,
376 wxT("shouldn't be used") );
378 // base class creates the icon for us initially but we could have destroyed
379 // it in DoClose(), recreate it if this was the case
383 // use maximal (in current Windows versions) timeout (but it will still
384 // disappear on its own)
385 return wxBalloonNotifMsgImpl::DoShow(title
, message
, 30, flags
);
388 bool wxManualNotifMsgImpl::DoClose()
390 if ( IsUsingOwnIcon() )
392 // we don't need the icon any more
395 else // using an existing icon
397 // just hide the balloon
398 ms_icon
->ShowBalloon("", "");
404 // ----------------------------------------------------------------------------
405 // wxAutoNotifMsgImpl
406 // ----------------------------------------------------------------------------
408 wxAutoNotifMsgImpl::wxAutoNotifMsgImpl(wxWindow
*win
)
409 : wxBalloonNotifMsgImpl(win
)
411 if ( ms_refCountIcon
!= -1 )
413 // This object will self-destruct and decrease the ref count of the
414 // icon when the notification is hidden.
415 new wxNotificationIconEvtHandler(ms_icon
);
420 wxAutoNotifMsgImpl::DoShow(const wxString
& title
,
421 const wxString
& message
,
425 wxASSERT_MSG( timeout
!= wxNotificationMessage::Timeout_Never
,
426 wxT("shouldn't be used") );
428 if ( timeout
== wxNotificationMessage::Timeout_Auto
)
430 // choose a value more or less in the middle of the allowed range
434 return wxBalloonNotifMsgImpl::DoShow(title
, message
, timeout
, flags
);
437 // ----------------------------------------------------------------------------
438 // wxNotificationMessage
439 // ----------------------------------------------------------------------------
442 bool wxNotificationMessage::ms_alwaysUseGeneric
= false;
445 wxTaskBarIcon
*wxNotificationMessage::UseTaskBarIcon(wxTaskBarIcon
*icon
)
447 return wxBalloonNotifMsgImpl::UseTaskBarIcon(icon
);
450 bool wxNotificationMessage::Show(int timeout
)
454 if ( !ms_alwaysUseGeneric
&& wxTheApp
->GetShell32Version() >= 500 )
456 if ( timeout
== Timeout_Never
)
457 m_impl
= new wxManualNotifMsgImpl(GetParent());
459 m_impl
= new wxAutoNotifMsgImpl(GetParent());
461 else // no support for balloon tooltips
463 m_impl
= new wxGenericNotifMsgImpl
;
466 //else: reuse the same implementation for the subsequent calls, it would
467 // be too confusing if it changed
469 return m_impl
->DoShow(GetTitle(), GetMessage(), timeout
, GetFlags());
472 bool wxNotificationMessage::Close()
474 wxCHECK_MSG( m_impl
, false, "must show the notification first" );
476 return m_impl
->DoClose();
479 wxNotificationMessage::~wxNotificationMessage()
484 #endif // wxUSE_NOTIFICATION_MESSAGE && wxUSE_TASKBARICON