1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/notifmsg.cpp
3 // Purpose: implementation of wxNotificationMessage for Windows
4 // Author: Vadim Zeitlin
7 // Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
26 // we can only use the native implementation if we have a working
27 // wxTaskBarIcon::ShowBalloon() method
28 #if wxUSE_NOTIFICATION_MESSAGE && \
29 wxUSE_TASKBARICON && wxUSE_TASKBARICON_BALLOONS
31 #include "wx/notifmsg.h"
34 #include "wx/toplevel.h"
36 #include "wx/string.h"
39 #include "wx/generic/notifmsg.h"
41 #include "wx/taskbar.h"
43 // ----------------------------------------------------------------------------
44 // different implementations used by wxNotificationMessage
45 // ----------------------------------------------------------------------------
47 // base class for all available implementations
52 virtual ~wxNotifMsgImpl() { }
54 virtual bool DoShow(const wxString
& title
,
55 const wxString
& message
,
58 virtual bool DoClose() = 0;
61 wxDECLARE_NO_COPY_CLASS(wxNotifMsgImpl
);
64 // implementation which is simply a bridge to wxGenericNotificationMessage
65 class wxGenericNotifMsgImpl
: public wxNotifMsgImpl
68 wxGenericNotifMsgImpl() : m_notif(new wxGenericNotificationMessage
) { }
69 virtual ~wxGenericNotifMsgImpl() { delete m_notif
; }
71 virtual bool DoShow(const wxString
& title
,
72 const wxString
& message
,
76 m_notif
->SetTitle(title
);
77 m_notif
->SetMessage(message
);
78 m_notif
->SetFlags(flags
);
79 return m_notif
->Show(timeout
);
82 virtual bool DoClose()
84 return m_notif
->Close();
88 wxGenericNotificationMessage
* const m_notif
;
91 // common base class for implementations using a taskbar icon and balloons
92 class wxBalloonNotifMsgImpl
: public wxNotifMsgImpl
95 // ctor sets up m_icon (using the icon of the top level parent of the given
96 // window) which can be used to show an attached balloon later by the
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 // sets up m_icon (doesn't do anything with the old value, caller beware)
110 void SetUpIcon(wxWindow
*win
);
113 static wxTaskBarIcon
*ms_iconToUse
;
115 // the icon we attach our notification to, either ms_iconToUse or a
116 // temporary one which we will destroy when done
117 wxTaskBarIcon
*m_icon
;
119 // should be only used if m_icon != NULL and indicates whether we should
124 // implementation for automatically hidden notifications
125 class wxAutoNotifMsgImpl
: public wxBalloonNotifMsgImpl
128 wxAutoNotifMsgImpl(wxWindow
*win
);
130 virtual bool DoShow(const wxString
& title
,
131 const wxString
& message
,
135 // can't close automatic notification [currently]
136 virtual bool DoClose() { return false; }
139 // implementation for manually closed notifications
140 class wxManualNotifMsgImpl
: public wxBalloonNotifMsgImpl
143 wxManualNotifMsgImpl(wxWindow
*win
);
144 virtual ~wxManualNotifMsgImpl();
146 virtual bool DoShow(const wxString
& title
,
147 const wxString
& message
,
150 virtual bool DoClose();
153 // store ctor parameter as we need it to recreate the icon later if we're
154 // closed and shown again
155 wxWindow
* const m_win
;
158 // ----------------------------------------------------------------------------
159 // custom event handler for task bar icons
160 // ----------------------------------------------------------------------------
162 // normally we'd just use a custom taskbar icon class but this is impossible
163 // because we can be asked to attach the notifications to an existing icon
164 // which we didn't create, hence we install a special event handler allowing us
165 // to get the events we need (and, crucially, to delete the icon when it's not
166 // needed any more) in any case
168 class wxNotificationIconEvtHandler
: public wxEvtHandler
171 wxNotificationIconEvtHandler(wxTaskBarIcon
*icon
);
174 void OnTimeout(wxTaskBarIconEvent
& event
);
175 void OnClick(wxTaskBarIconEvent
& event
);
180 wxTaskBarIcon
* const m_icon
;
182 wxDECLARE_NO_COPY_CLASS(wxNotificationIconEvtHandler
);
185 // ============================================================================
187 // ============================================================================
189 // ----------------------------------------------------------------------------
190 // wxNotificationIconEvtHandler
191 // ----------------------------------------------------------------------------
193 wxNotificationIconEvtHandler::wxNotificationIconEvtHandler(wxTaskBarIcon
*icon
)
198 wxEVT_TASKBAR_BALLOON_TIMEOUT
,
199 wxTaskBarIconEventHandler(wxNotificationIconEvtHandler::OnTimeout
),
206 wxEVT_TASKBAR_BALLOON_CLICK
,
207 wxTaskBarIconEventHandler(wxNotificationIconEvtHandler::OnClick
),
213 void wxNotificationIconEvtHandler::OnIconHidden()
221 wxNotificationIconEvtHandler::OnTimeout(wxTaskBarIconEvent
& WXUNUSED(event
))
226 void wxNotificationIconEvtHandler::OnClick(wxTaskBarIconEvent
& WXUNUSED(event
))
228 // TODO: generate an event notifying the user code?
233 // ----------------------------------------------------------------------------
234 // wxBalloonNotifMsgImpl
235 // ----------------------------------------------------------------------------
237 wxTaskBarIcon
*wxBalloonNotifMsgImpl::ms_iconToUse
= NULL
;
240 wxTaskBarIcon
*wxBalloonNotifMsgImpl::UseTaskBarIcon(wxTaskBarIcon
*icon
)
242 wxTaskBarIcon
* const iconOld
= ms_iconToUse
;
247 void wxBalloonNotifMsgImpl::SetUpIcon(wxWindow
*win
)
251 // use an existing icon
253 m_icon
= ms_iconToUse
;
255 else // no user-specified icon to attach to
257 // create our own one
259 m_icon
= new wxTaskBarIcon
;
261 // use the icon of the associated (or main, if none) frame
264 win
= wxGetTopLevelParent(win
);
266 win
= wxTheApp
->GetTopWindow();
269 const wxTopLevelWindow
* const
270 tlw
= wxDynamicCast(win
, wxTopLevelWindow
);
272 icon
= tlw
->GetIcon();
277 // we really must have some icon
278 icon
= wxIcon(wxT("wxICON_AAA"));
281 m_icon
->SetIcon(icon
);
286 wxBalloonNotifMsgImpl::DoShow(const wxString
& title
,
287 const wxString
& message
,
291 if ( !m_icon
->IsIconInstalled() )
293 // If we failed to install the icon (which does happen sometimes,
294 // although only in unusual circumstances, e.g. it happens regularly,
295 // albeit not constantly, if we're used soon after resume from suspend
296 // under Windows 7), we should not call ShowBalloon() because it would
297 // just assert and return and we must delete the icon ourselves because
298 // otherwise its associated wxTaskBarIconWindow would remain alive
299 // forever because we're not going to receive a notification about icon
300 // disappearance from the system if we failed to install it in the
308 timeout
*= 1000; // Windows expresses timeout in milliseconds
310 return m_icon
->ShowBalloon(title
, message
, timeout
, flags
);
313 // ----------------------------------------------------------------------------
314 // wxManualNotifMsgImpl
315 // ----------------------------------------------------------------------------
317 wxManualNotifMsgImpl::wxManualNotifMsgImpl(wxWindow
*win
)
318 : wxBalloonNotifMsgImpl(win
),
323 wxManualNotifMsgImpl::~wxManualNotifMsgImpl()
330 wxManualNotifMsgImpl::DoShow(const wxString
& title
,
331 const wxString
& message
,
332 int WXUNUSED_UNLESS_DEBUG(timeout
),
335 wxASSERT_MSG( timeout
== wxNotificationMessage::Timeout_Never
,
336 wxT("shouldn't be used") );
338 // base class creates the icon for us initially but we could have destroyed
339 // it in DoClose(), recreate it if this was the case
343 // use maximal (in current Windows versions) timeout (but it will still
344 // disappear on its own)
345 return wxBalloonNotifMsgImpl::DoShow(title
, message
, 30, flags
);
348 bool wxManualNotifMsgImpl::DoClose()
352 // we don't need the icon any more
355 else // using an existing icon
357 // just hide the balloon
358 m_icon
->ShowBalloon("", "");
366 // ----------------------------------------------------------------------------
367 // wxAutoNotifMsgImpl
368 // ----------------------------------------------------------------------------
370 wxAutoNotifMsgImpl::wxAutoNotifMsgImpl(wxWindow
*win
)
371 : wxBalloonNotifMsgImpl(win
)
375 // This object will self-destruct and also delete the icon when the
376 // notification is hidden.
377 new wxNotificationIconEvtHandler(m_icon
);
382 wxAutoNotifMsgImpl::DoShow(const wxString
& title
,
383 const wxString
& message
,
387 wxASSERT_MSG( timeout
!= wxNotificationMessage::Timeout_Never
,
388 wxT("shouldn't be used") );
390 if ( timeout
== wxNotificationMessage::Timeout_Auto
)
392 // choose a value more or less in the middle of the allowed range
396 return wxBalloonNotifMsgImpl::DoShow(title
, message
, timeout
, flags
);
399 // ----------------------------------------------------------------------------
400 // wxNotificationMessage
401 // ----------------------------------------------------------------------------
404 bool wxNotificationMessage::ms_alwaysUseGeneric
= false;
407 wxTaskBarIcon
*wxNotificationMessage::UseTaskBarIcon(wxTaskBarIcon
*icon
)
409 return wxBalloonNotifMsgImpl::UseTaskBarIcon(icon
);
412 bool wxNotificationMessage::Show(int timeout
)
416 if ( !ms_alwaysUseGeneric
&& wxTheApp
->GetShell32Version() >= 500 )
418 if ( timeout
== Timeout_Never
)
419 m_impl
= new wxManualNotifMsgImpl(GetParent());
421 m_impl
= new wxAutoNotifMsgImpl(GetParent());
423 else // no support for balloon tooltips
425 m_impl
= new wxGenericNotifMsgImpl
;
428 //else: reuse the same implementation for the subsequent calls, it would
429 // be too confusing if it changed
431 return m_impl
->DoShow(GetTitle(), GetMessage(), timeout
, GetFlags());
434 bool wxNotificationMessage::Close()
436 wxCHECK_MSG( m_impl
, false, "must show the notification first" );
438 return m_impl
->DoClose();
441 wxNotificationMessage::~wxNotificationMessage()
446 #endif // wxUSE_NOTIFICATION_MESSAGE && wxUSE_TASKBARICON