]> git.saurik.com Git - wxWidgets.git/blame - src/msw/notifmsg.cpp
Compilation fix for !wxUSE_OWNER_DRAWN.
[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
e2d5abbf
VZ
6// Copyright: (c) 2007 Vadim Zeitlin <vadim@wxwindows.org>
7// Licence: wxWindows licence
8///////////////////////////////////////////////////////////////////////////////
9
10// ============================================================================
11// declarations
12// ============================================================================
13
14// ----------------------------------------------------------------------------
15// headers
16// ----------------------------------------------------------------------------
17
18// for compilers that support precompilation, includes "wx.h".
19#include "wx/wxprec.h"
20
21#ifdef __BORLANDC__
22 #pragma hdrstop
23#endif
24
01b7f8f2
VZ
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
e2d5abbf 29
11a0827d
PC
30#include "wx/notifmsg.h"
31
e2d5abbf 32#ifndef WX_PRECOMP
11a0827d
PC
33 #include "wx/toplevel.h"
34 #include "wx/app.h"
e2d5abbf
VZ
35 #include "wx/string.h"
36#endif // WX_PRECOMP
37
e2d5abbf
VZ
38#include "wx/generic/notifmsg.h"
39
40#include "wx/taskbar.h"
41
42// ----------------------------------------------------------------------------
43// different implementations used by wxNotificationMessage
44// ----------------------------------------------------------------------------
45
46// base class for all available implementations
47class wxNotifMsgImpl
48{
49public:
50 wxNotifMsgImpl() { }
51 virtual ~wxNotifMsgImpl() { }
52
53 virtual bool DoShow(const wxString& title,
54 const wxString& message,
55 int timeout,
56 int flags) = 0;
57 virtual bool DoClose() = 0;
58
59private:
c0c133e1 60 wxDECLARE_NO_COPY_CLASS(wxNotifMsgImpl);
e2d5abbf
VZ
61};
62
63// implementation which is simply a bridge to wxGenericNotificationMessage
64class wxGenericNotifMsgImpl : public wxNotifMsgImpl
65{
66public:
67 wxGenericNotifMsgImpl() : m_notif(new wxGenericNotificationMessage) { }
68 virtual ~wxGenericNotifMsgImpl() { delete m_notif; }
69
70 virtual bool DoShow(const wxString& title,
71 const wxString& message,
72 int timeout,
73 int flags)
74 {
75 m_notif->SetTitle(title);
76 m_notif->SetMessage(message);
77 m_notif->SetFlags(flags);
78 return m_notif->Show(timeout);
79 }
80
81 virtual bool DoClose()
82 {
83 return m_notif->Close();
84 }
85
86private:
87 wxGenericNotificationMessage * const m_notif;
88};
89
90// common base class for implementations using a taskbar icon and balloons
91class wxBalloonNotifMsgImpl : public wxNotifMsgImpl
92{
93public:
3b4b952d
VZ
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.
e2d5abbf
VZ
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
e2d5abbf 108
3b4b952d
VZ
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()
112 {
113 return ms_refCountIcon != -1;
114 }
115
116 // Indicates that the taskbar icon we're using has been hidden and can be
117 // deleted.
118 //
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()
123 {
124 wxASSERT_MSG( ms_refCountIcon != -1,
125 wxS("Must not be called when not using own icon") );
126
127 if ( !--ms_refCountIcon )
128 {
129 delete ms_icon;
130 ms_icon = NULL;
131 }
132 }
e2d5abbf 133
3b4b952d
VZ
134protected:
135 // Creates a new icon if necessary, see the comment below.
136 void SetUpIcon(wxWindow *win);
e2d5abbf 137
e2d5abbf 138
3b4b952d
VZ
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;
e2d5abbf
VZ
155};
156
157// implementation for automatically hidden notifications
158class wxAutoNotifMsgImpl : public wxBalloonNotifMsgImpl
159{
160public:
161 wxAutoNotifMsgImpl(wxWindow *win);
162
163 virtual bool DoShow(const wxString& title,
164 const wxString& message,
165 int timeout,
166 int flags);
167
168 // can't close automatic notification [currently]
169 virtual bool DoClose() { return false; }
e2d5abbf
VZ
170};
171
172// implementation for manually closed notifications
173class wxManualNotifMsgImpl : public wxBalloonNotifMsgImpl
174{
175public:
176 wxManualNotifMsgImpl(wxWindow *win);
177 virtual ~wxManualNotifMsgImpl();
178
179 virtual bool DoShow(const wxString& title,
180 const wxString& message,
181 int timeout,
182 int flags);
183 virtual bool DoClose();
184
185private:
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;
189};
190
191// ----------------------------------------------------------------------------
192// custom event handler for task bar icons
193// ----------------------------------------------------------------------------
194
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
200
201class wxNotificationIconEvtHandler : public wxEvtHandler
202{
203public:
204 wxNotificationIconEvtHandler(wxTaskBarIcon *icon);
205
206private:
207 void OnTimeout(wxTaskBarIconEvent& event);
208 void OnClick(wxTaskBarIconEvent& event);
209
210 void OnIconHidden();
211
212
213 wxTaskBarIcon * const m_icon;
214
c0c133e1 215 wxDECLARE_NO_COPY_CLASS(wxNotificationIconEvtHandler);
e2d5abbf
VZ
216};
217
218// ============================================================================
219// implementation
220// ============================================================================
221
222// ----------------------------------------------------------------------------
223// wxNotificationIconEvtHandler
224// ----------------------------------------------------------------------------
225
226wxNotificationIconEvtHandler::wxNotificationIconEvtHandler(wxTaskBarIcon *icon)
227 : m_icon(icon)
228{
229 m_icon->Connect
230 (
231 wxEVT_TASKBAR_BALLOON_TIMEOUT,
232 wxTaskBarIconEventHandler(wxNotificationIconEvtHandler::OnTimeout),
233 NULL,
234 this
235 );
236
237 m_icon->Connect
238 (
239 wxEVT_TASKBAR_BALLOON_CLICK,
64336927 240 wxTaskBarIconEventHandler(wxNotificationIconEvtHandler::OnClick),
e2d5abbf
VZ
241 NULL,
242 this
243 );
244}
245
246void wxNotificationIconEvtHandler::OnIconHidden()
247{
3b4b952d 248 wxBalloonNotifMsgImpl::ReleaseIcon();
e2d5abbf
VZ
249
250 delete this;
251}
252
253void
254wxNotificationIconEvtHandler::OnTimeout(wxTaskBarIconEvent& WXUNUSED(event))
255{
256 OnIconHidden();
257}
258
259void wxNotificationIconEvtHandler::OnClick(wxTaskBarIconEvent& WXUNUSED(event))
260{
261 // TODO: generate an event notifying the user code?
262
263 OnIconHidden();
264}
265
266// ----------------------------------------------------------------------------
267// wxBalloonNotifMsgImpl
268// ----------------------------------------------------------------------------
269
3b4b952d
VZ
270wxTaskBarIcon *wxBalloonNotifMsgImpl::ms_icon = NULL;
271int wxBalloonNotifMsgImpl::ms_refCountIcon = 0;
e2d5abbf
VZ
272
273/* static */
274wxTaskBarIcon *wxBalloonNotifMsgImpl::UseTaskBarIcon(wxTaskBarIcon *icon)
275{
3b4b952d
VZ
276 wxTaskBarIcon * const iconOld = ms_icon;
277 ms_icon = icon;
278
279 // Don't use reference counting for the provided icon, we don't own it.
280 ms_refCountIcon = icon ? -1 : 0;
281
e2d5abbf
VZ
282 return iconOld;
283}
284
285void wxBalloonNotifMsgImpl::SetUpIcon(wxWindow *win)
286{
3b4b952d 287 if ( ms_icon )
e2d5abbf 288 {
3b4b952d
VZ
289 // Increment the reference count if we manage the icon on our own.
290 if ( ms_refCountIcon != -1 )
291 ms_refCountIcon++;
e2d5abbf 292 }
3b4b952d 293 else // Create a new icon.
e2d5abbf 294 {
3b4b952d
VZ
295 wxASSERT_MSG( ms_refCountIcon == 0,
296 wxS("Shouldn't reference not existent icon") );
297
298 ms_icon = new wxTaskBarIcon;
299 ms_refCountIcon = 1;
e2d5abbf
VZ
300
301 // use the icon of the associated (or main, if none) frame
302 wxIcon icon;
303 if ( win )
304 win = wxGetTopLevelParent(win);
305 if ( !win )
306 win = wxTheApp->GetTopWindow();
307 if ( win )
308 {
309 const wxTopLevelWindow * const
310 tlw = wxDynamicCast(win, wxTopLevelWindow);
311 if ( tlw )
312 icon = tlw->GetIcon();
313 }
314
315 if ( !icon.IsOk() )
316 {
317 // we really must have some icon
9a83f860 318 icon = wxIcon(wxT("wxICON_AAA"));
e2d5abbf
VZ
319 }
320
3b4b952d 321 ms_icon->SetIcon(icon);
e2d5abbf
VZ
322 }
323}
324
325bool
326wxBalloonNotifMsgImpl::DoShow(const wxString& title,
327 const wxString& message,
328 int timeout,
329 int flags)
330{
3b4b952d 331 if ( !ms_icon->IsIconInstalled() )
ac664fea
VZ
332 {
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
341 // first place.
3b4b952d
VZ
342 delete ms_icon;
343 ms_icon = NULL;
ac664fea
VZ
344
345 return false;
346 }
347
e2d5abbf
VZ
348 timeout *= 1000; // Windows expresses timeout in milliseconds
349
3b4b952d 350 return ms_icon->ShowBalloon(title, message, timeout, flags);
e2d5abbf
VZ
351}
352
353// ----------------------------------------------------------------------------
354// wxManualNotifMsgImpl
355// ----------------------------------------------------------------------------
356
357wxManualNotifMsgImpl::wxManualNotifMsgImpl(wxWindow *win)
358 : wxBalloonNotifMsgImpl(win),
359 m_win(win)
360{
361}
362
363wxManualNotifMsgImpl::~wxManualNotifMsgImpl()
364{
3b4b952d 365 if ( ms_icon )
e2d5abbf
VZ
366 DoClose();
367}
368
369bool
370wxManualNotifMsgImpl::DoShow(const wxString& title,
371 const wxString& message,
68753711 372 int WXUNUSED_UNLESS_DEBUG(timeout),
e2d5abbf
VZ
373 int flags)
374{
375 wxASSERT_MSG( timeout == wxNotificationMessage::Timeout_Never,
9a83f860 376 wxT("shouldn't be used") );
e2d5abbf
VZ
377
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
3b4b952d 380 if ( !ms_icon )
e2d5abbf
VZ
381 SetUpIcon(m_win);
382
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);
386}
387
388bool wxManualNotifMsgImpl::DoClose()
389{
3b4b952d 390 if ( IsUsingOwnIcon() )
e2d5abbf
VZ
391 {
392 // we don't need the icon any more
3b4b952d 393 ReleaseIcon();
e2d5abbf
VZ
394 }
395 else // using an existing icon
396 {
397 // just hide the balloon
3b4b952d 398 ms_icon->ShowBalloon("", "");
e2d5abbf
VZ
399 }
400
e2d5abbf
VZ
401 return true;
402}
403
404// ----------------------------------------------------------------------------
405// wxAutoNotifMsgImpl
406// ----------------------------------------------------------------------------
407
408wxAutoNotifMsgImpl::wxAutoNotifMsgImpl(wxWindow *win)
4dd8339b 409 : wxBalloonNotifMsgImpl(win)
e2d5abbf 410{
3b4b952d 411 if ( ms_refCountIcon != -1 )
4dd8339b 412 {
3b4b952d
VZ
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);
4dd8339b 416 }
e2d5abbf
VZ
417}
418
419bool
420wxAutoNotifMsgImpl::DoShow(const wxString& title,
421 const wxString& message,
422 int timeout,
423 int flags)
424{
425 wxASSERT_MSG( timeout != wxNotificationMessage::Timeout_Never,
9a83f860 426 wxT("shouldn't be used") );
e2d5abbf
VZ
427
428 if ( timeout == wxNotificationMessage::Timeout_Auto )
429 {
430 // choose a value more or less in the middle of the allowed range
431 timeout = 1;
432 }
433
434 return wxBalloonNotifMsgImpl::DoShow(title, message, timeout, flags);
435}
436
437// ----------------------------------------------------------------------------
438// wxNotificationMessage
439// ----------------------------------------------------------------------------
440
5e6b39c9
VZ
441/* static */
442bool wxNotificationMessage::ms_alwaysUseGeneric = false;
443
e2d5abbf
VZ
444/* static */
445wxTaskBarIcon *wxNotificationMessage::UseTaskBarIcon(wxTaskBarIcon *icon)
446{
447 return wxBalloonNotifMsgImpl::UseTaskBarIcon(icon);
448}
449
450bool wxNotificationMessage::Show(int timeout)
451{
452 if ( !m_impl )
453 {
5e6b39c9 454 if ( !ms_alwaysUseGeneric && wxTheApp->GetShell32Version() >= 500 )
e2d5abbf
VZ
455 {
456 if ( timeout == Timeout_Never )
457 m_impl = new wxManualNotifMsgImpl(GetParent());
458 else
459 m_impl = new wxAutoNotifMsgImpl(GetParent());
460 }
461 else // no support for balloon tooltips
462 {
463 m_impl = new wxGenericNotifMsgImpl;
464 }
465 }
466 //else: reuse the same implementation for the subsequent calls, it would
467 // be too confusing if it changed
468
469 return m_impl->DoShow(GetTitle(), GetMessage(), timeout, GetFlags());
470}
471
472bool wxNotificationMessage::Close()
473{
474 wxCHECK_MSG( m_impl, false, "must show the notification first" );
475
476 return m_impl->DoClose();
477}
478
479wxNotificationMessage::~wxNotificationMessage()
480{
481 delete m_impl;
482}
483
484#endif // wxUSE_NOTIFICATION_MESSAGE && wxUSE_TASKBARICON