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