]> git.saurik.com Git - wxWidgets.git/blame - src/msw/notifmsg.cpp
simplify code so it always returns the same object
[wxWidgets.git] / src / msw / notifmsg.cpp
CommitLineData
e2d5abbf
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/msw/notifmsg.cpp
3// Purpose: implementation of wxNotificationMessage for Windows
4// Author: Vadim Zeitlin
5// Created: 2007-12-01
6// RCS-ID: $Id$
7// Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
8// Licence: wxWindows licence
9///////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
19// for compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
01b7f8f2
VZ
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
e2d5abbf 30
11a0827d
PC
31#include "wx/notifmsg.h"
32
e2d5abbf 33#ifndef WX_PRECOMP
11a0827d
PC
34 #include "wx/toplevel.h"
35 #include "wx/app.h"
e2d5abbf
VZ
36 #include "wx/string.h"
37#endif // WX_PRECOMP
38
e2d5abbf
VZ
39#include "wx/generic/notifmsg.h"
40
41#include "wx/taskbar.h"
42
43// ----------------------------------------------------------------------------
44// different implementations used by wxNotificationMessage
45// ----------------------------------------------------------------------------
46
47// base class for all available implementations
48class wxNotifMsgImpl
49{
50public:
51 wxNotifMsgImpl() { }
52 virtual ~wxNotifMsgImpl() { }
53
54 virtual bool DoShow(const wxString& title,
55 const wxString& message,
56 int timeout,
57 int flags) = 0;
58 virtual bool DoClose() = 0;
59
60private:
c0c133e1 61 wxDECLARE_NO_COPY_CLASS(wxNotifMsgImpl);
e2d5abbf
VZ
62};
63
64// implementation which is simply a bridge to wxGenericNotificationMessage
65class wxGenericNotifMsgImpl : public wxNotifMsgImpl
66{
67public:
68 wxGenericNotifMsgImpl() : m_notif(new wxGenericNotificationMessage) { }
69 virtual ~wxGenericNotifMsgImpl() { delete m_notif; }
70
71 virtual bool DoShow(const wxString& title,
72 const wxString& message,
73 int timeout,
74 int flags)
75 {
76 m_notif->SetTitle(title);
77 m_notif->SetMessage(message);
78 m_notif->SetFlags(flags);
79 return m_notif->Show(timeout);
80 }
81
82 virtual bool DoClose()
83 {
84 return m_notif->Close();
85 }
86
87private:
88 wxGenericNotificationMessage * const m_notif;
89};
90
91// common base class for implementations using a taskbar icon and balloons
92class wxBalloonNotifMsgImpl : public wxNotifMsgImpl
93{
94public:
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
97 // derived classes
98 wxBalloonNotifMsgImpl(wxWindow *win) { SetUpIcon(win); }
99
100 // implementation of wxNotificationMessage method with the same name
101 static wxTaskBarIcon *UseTaskBarIcon(wxTaskBarIcon *icon);
102
103 virtual bool DoShow(const wxString& title,
104 const wxString& message,
105 int timeout,
106 int flags);
107
108protected:
109 // sets up m_icon (doesn't do anything with the old value, caller beware)
110 void SetUpIcon(wxWindow *win);
111
112
113 static wxTaskBarIcon *ms_iconToUse;
114
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;
118
119 // should be only used if m_icon != NULL and indicates whether we should
120 // delete it
121 bool m_ownsIcon;
122};
123
124// implementation for automatically hidden notifications
125class wxAutoNotifMsgImpl : public wxBalloonNotifMsgImpl
126{
127public:
128 wxAutoNotifMsgImpl(wxWindow *win);
129
130 virtual bool DoShow(const wxString& title,
131 const wxString& message,
132 int timeout,
133 int flags);
134
135 // can't close automatic notification [currently]
136 virtual bool DoClose() { return false; }
e2d5abbf
VZ
137};
138
139// implementation for manually closed notifications
140class wxManualNotifMsgImpl : public wxBalloonNotifMsgImpl
141{
142public:
143 wxManualNotifMsgImpl(wxWindow *win);
144 virtual ~wxManualNotifMsgImpl();
145
146 virtual bool DoShow(const wxString& title,
147 const wxString& message,
148 int timeout,
149 int flags);
150 virtual bool DoClose();
151
152private:
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;
156};
157
158// ----------------------------------------------------------------------------
159// custom event handler for task bar icons
160// ----------------------------------------------------------------------------
161
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
167
168class wxNotificationIconEvtHandler : public wxEvtHandler
169{
170public:
171 wxNotificationIconEvtHandler(wxTaskBarIcon *icon);
172
173private:
174 void OnTimeout(wxTaskBarIconEvent& event);
175 void OnClick(wxTaskBarIconEvent& event);
176
177 void OnIconHidden();
178
179
180 wxTaskBarIcon * const m_icon;
181
c0c133e1 182 wxDECLARE_NO_COPY_CLASS(wxNotificationIconEvtHandler);
e2d5abbf
VZ
183};
184
185// ============================================================================
186// implementation
187// ============================================================================
188
189// ----------------------------------------------------------------------------
190// wxNotificationIconEvtHandler
191// ----------------------------------------------------------------------------
192
193wxNotificationIconEvtHandler::wxNotificationIconEvtHandler(wxTaskBarIcon *icon)
194 : m_icon(icon)
195{
196 m_icon->Connect
197 (
198 wxEVT_TASKBAR_BALLOON_TIMEOUT,
199 wxTaskBarIconEventHandler(wxNotificationIconEvtHandler::OnTimeout),
200 NULL,
201 this
202 );
203
204 m_icon->Connect
205 (
206 wxEVT_TASKBAR_BALLOON_CLICK,
64336927 207 wxTaskBarIconEventHandler(wxNotificationIconEvtHandler::OnClick),
e2d5abbf
VZ
208 NULL,
209 this
210 );
211}
212
213void wxNotificationIconEvtHandler::OnIconHidden()
214{
215 delete m_icon;
216
217 delete this;
218}
219
220void
221wxNotificationIconEvtHandler::OnTimeout(wxTaskBarIconEvent& WXUNUSED(event))
222{
223 OnIconHidden();
224}
225
226void wxNotificationIconEvtHandler::OnClick(wxTaskBarIconEvent& WXUNUSED(event))
227{
228 // TODO: generate an event notifying the user code?
229
230 OnIconHidden();
231}
232
233// ----------------------------------------------------------------------------
234// wxBalloonNotifMsgImpl
235// ----------------------------------------------------------------------------
236
237wxTaskBarIcon *wxBalloonNotifMsgImpl::ms_iconToUse = NULL;
238
239/* static */
240wxTaskBarIcon *wxBalloonNotifMsgImpl::UseTaskBarIcon(wxTaskBarIcon *icon)
241{
242 wxTaskBarIcon * const iconOld = ms_iconToUse;
243 ms_iconToUse = icon;
244 return iconOld;
245}
246
247void wxBalloonNotifMsgImpl::SetUpIcon(wxWindow *win)
248{
249 if ( ms_iconToUse )
250 {
251 // use an existing icon
252 m_ownsIcon = false;
253 m_icon = ms_iconToUse;
254 }
255 else // no user-specified icon to attach to
256 {
257 // create our own one
258 m_ownsIcon = true;
259 m_icon = new wxTaskBarIcon;
260
261 // use the icon of the associated (or main, if none) frame
262 wxIcon icon;
263 if ( win )
264 win = wxGetTopLevelParent(win);
265 if ( !win )
266 win = wxTheApp->GetTopWindow();
267 if ( win )
268 {
269 const wxTopLevelWindow * const
270 tlw = wxDynamicCast(win, wxTopLevelWindow);
271 if ( tlw )
272 icon = tlw->GetIcon();
273 }
274
275 if ( !icon.IsOk() )
276 {
277 // we really must have some icon
9a83f860 278 icon = wxIcon(wxT("wxICON_AAA"));
e2d5abbf
VZ
279 }
280
281 m_icon->SetIcon(icon);
282 }
283}
284
285bool
286wxBalloonNotifMsgImpl::DoShow(const wxString& title,
287 const wxString& message,
288 int timeout,
289 int flags)
290{
ac664fea
VZ
291 if ( !m_icon->IsIconInstalled() )
292 {
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
301 // first place.
302 delete m_icon;
303 m_icon = NULL;
304
305 return false;
306 }
307
e2d5abbf
VZ
308 timeout *= 1000; // Windows expresses timeout in milliseconds
309
310 return m_icon->ShowBalloon(title, message, timeout, flags);
311}
312
313// ----------------------------------------------------------------------------
314// wxManualNotifMsgImpl
315// ----------------------------------------------------------------------------
316
317wxManualNotifMsgImpl::wxManualNotifMsgImpl(wxWindow *win)
318 : wxBalloonNotifMsgImpl(win),
319 m_win(win)
320{
321}
322
323wxManualNotifMsgImpl::~wxManualNotifMsgImpl()
324{
325 if ( m_icon )
326 DoClose();
327}
328
329bool
330wxManualNotifMsgImpl::DoShow(const wxString& title,
331 const wxString& message,
68753711 332 int WXUNUSED_UNLESS_DEBUG(timeout),
e2d5abbf
VZ
333 int flags)
334{
335 wxASSERT_MSG( timeout == wxNotificationMessage::Timeout_Never,
9a83f860 336 wxT("shouldn't be used") );
e2d5abbf
VZ
337
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
340 if ( !m_icon )
341 SetUpIcon(m_win);
342
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);
346}
347
348bool wxManualNotifMsgImpl::DoClose()
349{
350 if ( m_ownsIcon )
351 {
352 // we don't need the icon any more
353 delete m_icon;
354 }
355 else // using an existing icon
356 {
357 // just hide the balloon
358 m_icon->ShowBalloon("", "");
359 }
360
361 m_icon = NULL;
362
363 return true;
364}
365
366// ----------------------------------------------------------------------------
367// wxAutoNotifMsgImpl
368// ----------------------------------------------------------------------------
369
370wxAutoNotifMsgImpl::wxAutoNotifMsgImpl(wxWindow *win)
4dd8339b 371 : wxBalloonNotifMsgImpl(win)
e2d5abbf 372{
4dd8339b
VZ
373 if ( m_ownsIcon )
374 {
375 // This object will self-destruct and also delete the icon when the
376 // notification is hidden.
377 new wxNotificationIconEvtHandler(m_icon);
378 }
e2d5abbf
VZ
379}
380
381bool
382wxAutoNotifMsgImpl::DoShow(const wxString& title,
383 const wxString& message,
384 int timeout,
385 int flags)
386{
387 wxASSERT_MSG( timeout != wxNotificationMessage::Timeout_Never,
9a83f860 388 wxT("shouldn't be used") );
e2d5abbf
VZ
389
390 if ( timeout == wxNotificationMessage::Timeout_Auto )
391 {
392 // choose a value more or less in the middle of the allowed range
393 timeout = 1;
394 }
395
396 return wxBalloonNotifMsgImpl::DoShow(title, message, timeout, flags);
397}
398
399// ----------------------------------------------------------------------------
400// wxNotificationMessage
401// ----------------------------------------------------------------------------
402
5e6b39c9
VZ
403/* static */
404bool wxNotificationMessage::ms_alwaysUseGeneric = false;
405
e2d5abbf
VZ
406/* static */
407wxTaskBarIcon *wxNotificationMessage::UseTaskBarIcon(wxTaskBarIcon *icon)
408{
409 return wxBalloonNotifMsgImpl::UseTaskBarIcon(icon);
410}
411
412bool wxNotificationMessage::Show(int timeout)
413{
414 if ( !m_impl )
415 {
5e6b39c9 416 if ( !ms_alwaysUseGeneric && wxTheApp->GetShell32Version() >= 500 )
e2d5abbf
VZ
417 {
418 if ( timeout == Timeout_Never )
419 m_impl = new wxManualNotifMsgImpl(GetParent());
420 else
421 m_impl = new wxAutoNotifMsgImpl(GetParent());
422 }
423 else // no support for balloon tooltips
424 {
425 m_impl = new wxGenericNotifMsgImpl;
426 }
427 }
428 //else: reuse the same implementation for the subsequent calls, it would
429 // be too confusing if it changed
430
431 return m_impl->DoShow(GetTitle(), GetMessage(), timeout, GetFlags());
432}
433
434bool wxNotificationMessage::Close()
435{
436 wxCHECK_MSG( m_impl, false, "must show the notification first" );
437
438 return m_impl->DoClose();
439}
440
441wxNotificationMessage::~wxNotificationMessage()
442{
443 delete m_impl;
444}
445
446#endif // wxUSE_NOTIFICATION_MESSAGE && wxUSE_TASKBARICON