correct the wxEVT_TASKBAR_BALLOON_CLICK handler name (it doesn't change anything...
[wxWidgets.git] / src / msw / notifmsg.cpp
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
26 #if wxUSE_NOTIFICATION_MESSAGE && wxUSE_TASKBARICON
27
28 #ifndef WX_PRECOMP
29 #include "wx/string.h"
30 #endif // WX_PRECOMP
31
32 #include "wx/notifmsg.h"
33 #include "wx/generic/notifmsg.h"
34
35 #include "wx/taskbar.h"
36
37 // ----------------------------------------------------------------------------
38 // different implementations used by wxNotificationMessage
39 // ----------------------------------------------------------------------------
40
41 // base class for all available implementations
42 class wxNotifMsgImpl
43 {
44 public:
45 wxNotifMsgImpl() { }
46 virtual ~wxNotifMsgImpl() { }
47
48 virtual bool DoShow(const wxString& title,
49 const wxString& message,
50 int timeout,
51 int flags) = 0;
52 virtual bool DoClose() = 0;
53
54 private:
55 DECLARE_NO_COPY_CLASS(wxNotifMsgImpl)
56 };
57
58 // implementation which is simply a bridge to wxGenericNotificationMessage
59 class wxGenericNotifMsgImpl : public wxNotifMsgImpl
60 {
61 public:
62 wxGenericNotifMsgImpl() : m_notif(new wxGenericNotificationMessage) { }
63 virtual ~wxGenericNotifMsgImpl() { delete m_notif; }
64
65 virtual bool DoShow(const wxString& title,
66 const wxString& message,
67 int timeout,
68 int flags)
69 {
70 m_notif->SetTitle(title);
71 m_notif->SetMessage(message);
72 m_notif->SetFlags(flags);
73 return m_notif->Show(timeout);
74 }
75
76 virtual bool DoClose()
77 {
78 return m_notif->Close();
79 }
80
81 private:
82 wxGenericNotificationMessage * const m_notif;
83 };
84
85 // common base class for implementations using a taskbar icon and balloons
86 class wxBalloonNotifMsgImpl : public wxNotifMsgImpl
87 {
88 public:
89 // ctor sets up m_icon (using the icon of the top level parent of the given
90 // window) which can be used to show an attached balloon later by the
91 // derived classes
92 wxBalloonNotifMsgImpl(wxWindow *win) { SetUpIcon(win); }
93
94 // implementation of wxNotificationMessage method with the same name
95 static wxTaskBarIcon *UseTaskBarIcon(wxTaskBarIcon *icon);
96
97 virtual bool DoShow(const wxString& title,
98 const wxString& message,
99 int timeout,
100 int flags);
101
102 protected:
103 // sets up m_icon (doesn't do anything with the old value, caller beware)
104 void SetUpIcon(wxWindow *win);
105
106
107 static wxTaskBarIcon *ms_iconToUse;
108
109 // the icon we attach our notification to, either ms_iconToUse or a
110 // temporary one which we will destroy when done
111 wxTaskBarIcon *m_icon;
112
113 // should be only used if m_icon != NULL and indicates whether we should
114 // delete it
115 bool m_ownsIcon;
116 };
117
118 // implementation for automatically hidden notifications
119 class wxAutoNotifMsgImpl : public wxBalloonNotifMsgImpl
120 {
121 public:
122 wxAutoNotifMsgImpl(wxWindow *win);
123
124 virtual bool DoShow(const wxString& title,
125 const wxString& message,
126 int timeout,
127 int flags);
128
129 // can't close automatic notification [currently]
130 virtual bool DoClose() { return false; }
131
132 private:
133 // custom event handler connected to m_icon which will receive the icon
134 // close event and delete it and itself when it happens
135 wxEvtHandler * const m_iconEvtHandler;
136 };
137
138 // implementation for manually closed notifications
139 class wxManualNotifMsgImpl : public wxBalloonNotifMsgImpl
140 {
141 public:
142 wxManualNotifMsgImpl(wxWindow *win);
143 virtual ~wxManualNotifMsgImpl();
144
145 virtual bool DoShow(const wxString& title,
146 const wxString& message,
147 int timeout,
148 int flags);
149 virtual bool DoClose();
150
151 private:
152 // store ctor parameter as we need it to recreate the icon later if we're
153 // closed and shown again
154 wxWindow * const m_win;
155 };
156
157 // ----------------------------------------------------------------------------
158 // custom event handler for task bar icons
159 // ----------------------------------------------------------------------------
160
161 // normally we'd just use a custom taskbar icon class but this is impossible
162 // because we can be asked to attach the notifications to an existing icon
163 // which we didn't create, hence we install a special event handler allowing us
164 // to get the events we need (and, crucially, to delete the icon when it's not
165 // needed any more) in any case
166
167 class wxNotificationIconEvtHandler : public wxEvtHandler
168 {
169 public:
170 wxNotificationIconEvtHandler(wxTaskBarIcon *icon);
171
172 private:
173 void OnTimeout(wxTaskBarIconEvent& event);
174 void OnClick(wxTaskBarIconEvent& event);
175
176 void OnIconHidden();
177
178
179 wxTaskBarIcon * const m_icon;
180
181 DECLARE_NO_COPY_CLASS(wxNotificationIconEvtHandler)
182 };
183
184 // ============================================================================
185 // implementation
186 // ============================================================================
187
188 // ----------------------------------------------------------------------------
189 // wxNotificationIconEvtHandler
190 // ----------------------------------------------------------------------------
191
192 wxNotificationIconEvtHandler::wxNotificationIconEvtHandler(wxTaskBarIcon *icon)
193 : m_icon(icon)
194 {
195 m_icon->Connect
196 (
197 wxEVT_TASKBAR_BALLOON_TIMEOUT,
198 wxTaskBarIconEventHandler(wxNotificationIconEvtHandler::OnTimeout),
199 NULL,
200 this
201 );
202
203 m_icon->Connect
204 (
205 wxEVT_TASKBAR_BALLOON_CLICK,
206 wxTaskBarIconEventHandler(wxNotificationIconEvtHandler::OnClick),
207 NULL,
208 this
209 );
210 }
211
212 void wxNotificationIconEvtHandler::OnIconHidden()
213 {
214 delete m_icon;
215
216 delete this;
217 }
218
219 void
220 wxNotificationIconEvtHandler::OnTimeout(wxTaskBarIconEvent& WXUNUSED(event))
221 {
222 OnIconHidden();
223 }
224
225 void wxNotificationIconEvtHandler::OnClick(wxTaskBarIconEvent& WXUNUSED(event))
226 {
227 // TODO: generate an event notifying the user code?
228
229 OnIconHidden();
230 }
231
232 // ----------------------------------------------------------------------------
233 // wxBalloonNotifMsgImpl
234 // ----------------------------------------------------------------------------
235
236 wxTaskBarIcon *wxBalloonNotifMsgImpl::ms_iconToUse = NULL;
237
238 /* static */
239 wxTaskBarIcon *wxBalloonNotifMsgImpl::UseTaskBarIcon(wxTaskBarIcon *icon)
240 {
241 wxTaskBarIcon * const iconOld = ms_iconToUse;
242 ms_iconToUse = icon;
243 return iconOld;
244 }
245
246 void wxBalloonNotifMsgImpl::SetUpIcon(wxWindow *win)
247 {
248 if ( ms_iconToUse )
249 {
250 // use an existing icon
251 m_ownsIcon = false;
252 m_icon = ms_iconToUse;
253 }
254 else // no user-specified icon to attach to
255 {
256 // create our own one
257 m_ownsIcon = true;
258 m_icon = new wxTaskBarIcon;
259
260 // use the icon of the associated (or main, if none) frame
261 wxIcon icon;
262 if ( win )
263 win = wxGetTopLevelParent(win);
264 if ( !win )
265 win = wxTheApp->GetTopWindow();
266 if ( win )
267 {
268 const wxTopLevelWindow * const
269 tlw = wxDynamicCast(win, wxTopLevelWindow);
270 if ( tlw )
271 icon = tlw->GetIcon();
272 }
273
274 if ( !icon.IsOk() )
275 {
276 // we really must have some icon
277 icon = wxIcon(_T("wxICON_AAA"));
278 }
279
280 m_icon->SetIcon(icon);
281 }
282 }
283
284 bool
285 wxBalloonNotifMsgImpl::DoShow(const wxString& title,
286 const wxString& message,
287 int timeout,
288 int flags)
289 {
290 timeout *= 1000; // Windows expresses timeout in milliseconds
291
292 return m_icon->ShowBalloon(title, message, timeout, flags);
293 }
294
295 // ----------------------------------------------------------------------------
296 // wxManualNotifMsgImpl
297 // ----------------------------------------------------------------------------
298
299 wxManualNotifMsgImpl::wxManualNotifMsgImpl(wxWindow *win)
300 : wxBalloonNotifMsgImpl(win),
301 m_win(win)
302 {
303 }
304
305 wxManualNotifMsgImpl::~wxManualNotifMsgImpl()
306 {
307 if ( m_icon )
308 DoClose();
309 }
310
311 bool
312 wxManualNotifMsgImpl::DoShow(const wxString& title,
313 const wxString& message,
314 int timeout,
315 int flags)
316 {
317 wxASSERT_MSG( timeout == wxNotificationMessage::Timeout_Never,
318 _T("shouldn't be used") );
319
320 // base class creates the icon for us initially but we could have destroyed
321 // it in DoClose(), recreate it if this was the case
322 if ( !m_icon )
323 SetUpIcon(m_win);
324
325 // use maximal (in current Windows versions) timeout (but it will still
326 // disappear on its own)
327 return wxBalloonNotifMsgImpl::DoShow(title, message, 30, flags);
328 }
329
330 bool wxManualNotifMsgImpl::DoClose()
331 {
332 if ( m_ownsIcon )
333 {
334 // we don't need the icon any more
335 delete m_icon;
336 }
337 else // using an existing icon
338 {
339 // just hide the balloon
340 m_icon->ShowBalloon("", "");
341 }
342
343 m_icon = NULL;
344
345 return true;
346 }
347
348 // ----------------------------------------------------------------------------
349 // wxAutoNotifMsgImpl
350 // ----------------------------------------------------------------------------
351
352 wxAutoNotifMsgImpl::wxAutoNotifMsgImpl(wxWindow *win)
353 : wxBalloonNotifMsgImpl(win),
354 m_iconEvtHandler(new wxNotificationIconEvtHandler(m_icon))
355 {
356 }
357
358 bool
359 wxAutoNotifMsgImpl::DoShow(const wxString& title,
360 const wxString& message,
361 int timeout,
362 int flags)
363 {
364 wxASSERT_MSG( timeout != wxNotificationMessage::Timeout_Never,
365 _T("shouldn't be used") );
366
367 if ( timeout == wxNotificationMessage::Timeout_Auto )
368 {
369 // choose a value more or less in the middle of the allowed range
370 timeout = 1;
371 }
372
373 return wxBalloonNotifMsgImpl::DoShow(title, message, timeout, flags);
374 }
375
376 // ----------------------------------------------------------------------------
377 // wxNotificationMessage
378 // ----------------------------------------------------------------------------
379
380 /* static */
381 wxTaskBarIcon *wxNotificationMessage::UseTaskBarIcon(wxTaskBarIcon *icon)
382 {
383 return wxBalloonNotifMsgImpl::UseTaskBarIcon(icon);
384 }
385
386 bool wxNotificationMessage::Show(int timeout)
387 {
388 if ( !m_impl )
389 {
390 if ( wxTheApp->GetShell32Version() >= 500 )
391 {
392 if ( timeout == Timeout_Never )
393 m_impl = new wxManualNotifMsgImpl(GetParent());
394 else
395 m_impl = new wxAutoNotifMsgImpl(GetParent());
396 }
397 else // no support for balloon tooltips
398 {
399 m_impl = new wxGenericNotifMsgImpl;
400 }
401 }
402 //else: reuse the same implementation for the subsequent calls, it would
403 // be too confusing if it changed
404
405 return m_impl->DoShow(GetTitle(), GetMessage(), timeout, GetFlags());
406 }
407
408 bool wxNotificationMessage::Close()
409 {
410 wxCHECK_MSG( m_impl, false, "must show the notification first" );
411
412 return m_impl->DoClose();
413 }
414
415 wxNotificationMessage::~wxNotificationMessage()
416 {
417 delete m_impl;
418 }
419
420 #endif // wxUSE_NOTIFICATION_MESSAGE && wxUSE_TASKBARICON