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