]> git.saurik.com Git - wxWidgets.git/blob - src/msw/taskbar.cpp
added MSW-specific wxTaskBarIcon::ShowBalloon() method; use it in the taskbar sample...
[wxWidgets.git] / src / msw / taskbar.cpp
1 /////////////////////////////////////////////////////////////////////////
2 // File: src/msw/taskbar.cpp
3 // Purpose: Implements wxTaskBarIcon class for manipulating icons on
4 // the Windows task bar.
5 // Author: Julian Smart
6 // Modified by: Vaclav Slavik
7 // Created: 24/3/98
8 // RCS-ID: $Id$
9 // Copyright: (c)
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////
12
13 // For compilers that support precompilation, includes "wx.h".
14 #include "wx/wxprec.h"
15
16 #ifdef __BORLANDC__
17 #pragma hdrstop
18 #endif
19
20 #if wxUSE_TASKBARICON
21
22 #ifndef WX_PRECOMP
23 #include "wx/window.h"
24 #include "wx/frame.h"
25 #include "wx/utils.h"
26 #include "wx/menu.h"
27 #endif
28
29 #include "wx/msw/wrapshl.h"
30
31 #include <string.h>
32 #include "wx/taskbar.h"
33 #include "wx/dynlib.h"
34
35 // initialized on demand
36 static UINT gs_msgTaskbar = 0;
37 static UINT gs_msgRestartTaskbar = 0;
38
39
40 IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler)
41
42 // ============================================================================
43 // implementation
44 // ============================================================================
45
46 // wrapper around Shell_NotifyIcon(): this function is not present in Win95
47 // shell32.dll so load it dynamically to allow programs using wxTaskBarIcon to
48 // start under this OS
49 static BOOL wxShellNotifyIcon(DWORD dwMessage, NOTIFYICONDATA *pData)
50 {
51 #if wxUSE_DYNLIB_CLASS
52 typedef BOOL (WINAPI *Shell_NotifyIcon_t)(DWORD, NOTIFYICONDATA *);
53
54 static Shell_NotifyIcon_t s_pfnShell_NotifyIcon = NULL;
55 static bool s_initialized = false;
56 if ( !s_initialized )
57 {
58 s_initialized = true;
59
60 wxLogNull noLog;
61 wxDynamicLibrary dllShell("shell32.dll");
62 if ( dllShell.IsLoaded() )
63 {
64 wxDL_INIT_FUNC_AW(s_pfn, Shell_NotifyIcon, dllShell);
65 }
66
67 // NB: it's ok to destroy dllShell here, we link to shell32.dll
68 // implicitly so it won't be unloaded
69 }
70
71 return s_pfnShell_NotifyIcon ? (*s_pfnShell_NotifyIcon)(dwMessage, pData)
72 : FALSE;
73 #else // !wxUSE_DYNLIB_CLASS
74 return Shell_NotifyIcon(dwMessage, pData);
75 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
76 }
77
78 // ----------------------------------------------------------------------------
79 // wxTaskBarIconWindow: helper window
80 // ----------------------------------------------------------------------------
81
82 // NB: this class serves two purposes:
83 // 1. win32 needs a HWND associated with taskbar icon, this provides it
84 // 2. we need wxTopLevelWindow so that the app doesn't exit when
85 // last frame is closed but there still is a taskbar icon
86 class wxTaskBarIconWindow : public wxFrame
87 {
88 public:
89 wxTaskBarIconWindow(wxTaskBarIcon *icon)
90 : wxFrame(NULL, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0),
91 m_icon(icon)
92 {
93 }
94
95 WXLRESULT MSWWindowProc(WXUINT msg,
96 WXWPARAM wParam, WXLPARAM lParam)
97 {
98 if (msg == gs_msgRestartTaskbar || msg == gs_msgTaskbar)
99 {
100 return m_icon->WindowProc(msg, wParam, lParam);
101 }
102 else
103 {
104 return wxFrame::MSWWindowProc(msg, wParam, lParam);
105 }
106 }
107
108 private:
109 wxTaskBarIcon *m_icon;
110 };
111
112
113 // ----------------------------------------------------------------------------
114 // NotifyIconData: wrapper around NOTIFYICONDATA
115 // ----------------------------------------------------------------------------
116
117 struct NotifyIconData : public NOTIFYICONDATA
118 {
119 NotifyIconData(WXHWND hwnd)
120 {
121 memset(this, 0, sizeof(NOTIFYICONDATA));
122 cbSize = sizeof(NOTIFYICONDATA);
123 hWnd = (HWND) hwnd;
124 uCallbackMessage = gs_msgTaskbar;
125 uFlags = NIF_MESSAGE;
126
127 // we use the same id for all taskbar icons as we don't need it to
128 // distinguish between them
129 uID = 99;
130 }
131 };
132
133 // ----------------------------------------------------------------------------
134 // wxTaskBarIcon
135 // ----------------------------------------------------------------------------
136
137 wxTaskBarIcon::wxTaskBarIcon()
138 {
139 m_win = NULL;
140 m_iconAdded = false;
141 RegisterWindowMessages();
142 }
143
144 wxTaskBarIcon::~wxTaskBarIcon()
145 {
146 if (m_iconAdded)
147 RemoveIcon();
148
149 if (m_win)
150 m_win->Destroy();
151 }
152
153 // Operations
154 bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
155 {
156 // NB: we have to create the window lazily because of backward compatibility,
157 // old applications may create a wxTaskBarIcon instance before wxApp
158 // is initialized (as samples/taskbar used to do)
159 if (!m_win)
160 {
161 m_win = new wxTaskBarIconWindow(this);
162 }
163
164 m_icon = icon;
165 m_strTooltip = tooltip;
166
167 NotifyIconData notifyData(GetHwndOf(m_win));
168
169 if (icon.Ok())
170 {
171 notifyData.uFlags |= NIF_ICON;
172 notifyData.hIcon = GetHiconOf(icon);
173 }
174
175 // set NIF_TIP even for an empty tooltip: otherwise it would be impossible
176 // to remove an existing tooltip using this function
177 notifyData.uFlags |= NIF_TIP;
178 if ( !tooltip.empty() )
179 {
180 wxStrncpy(notifyData.szTip, tooltip.wx_str(), WXSIZEOF(notifyData.szTip));
181 }
182
183 bool ok = wxShellNotifyIcon(m_iconAdded ? NIM_MODIFY
184 : NIM_ADD, &notifyData) != 0;
185
186 if ( !m_iconAdded && ok )
187 m_iconAdded = true;
188
189 return ok;
190 }
191
192 bool
193 wxTaskBarIcon::ShowBalloon(const wxString& title,
194 const wxString& text,
195 unsigned msec,
196 int flags)
197 {
198 wxCHECK_MSG( m_iconAdded, false,
199 _T("can't be used before the icon is created") );
200
201 NotifyIconData notifyData(GetHwndOf(m_win));
202 notifyData.uFlags |= NIF_INFO;
203 notifyData.uTimeout = msec;
204 wxStrncpy(notifyData.szInfo, text.wx_str(), WXSIZEOF(notifyData.szInfo));
205 wxStrncpy(notifyData.szInfoTitle, title.wx_str(),
206 WXSIZEOF(notifyData.szInfoTitle));
207
208 if ( flags & wxICON_INFORMATION )
209 notifyData.dwInfoFlags |= NIIF_INFO;
210 else if ( flags & wxICON_WARNING )
211 notifyData.dwInfoFlags |= NIIF_WARNING;
212 else if ( flags & wxICON_ERROR )
213 notifyData.dwInfoFlags |= NIIF_ERROR;
214
215 return wxShellNotifyIcon(NIM_MODIFY, &notifyData) != 0;
216 }
217
218 bool wxTaskBarIcon::RemoveIcon()
219 {
220 if (!m_iconAdded)
221 return false;
222
223 m_iconAdded = false;
224
225 NotifyIconData notifyData(GetHwndOf(m_win));
226
227 return wxShellNotifyIcon(NIM_DELETE, &notifyData) != 0;
228 }
229
230 #if wxUSE_MENUS
231 bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
232 {
233 wxASSERT_MSG( m_win != NULL, _T("taskbar icon not initialized") );
234
235 static bool s_inPopup = false;
236
237 if (s_inPopup)
238 return false;
239
240 s_inPopup = true;
241
242 int x, y;
243 wxGetMousePosition(&x, &y);
244
245 m_win->Move(x, y);
246
247 m_win->PushEventHandler(this);
248
249 menu->UpdateUI();
250
251 // the SetForegroundWindow() and PostMessage() calls are needed to work
252 // around Win32 bug with the popup menus shown for the notifications as
253 // documented at http://support.microsoft.com/kb/q135788/
254 ::SetForegroundWindow(GetHwndOf(m_win));
255
256 bool rval = m_win->PopupMenu(menu, 0, 0);
257
258 ::PostMessage(GetHwndOf(m_win), WM_NULL, 0, 0L);
259
260 m_win->PopEventHandler(false);
261
262 s_inPopup = false;
263
264 return rval;
265 }
266 #endif // wxUSE_MENUS
267
268 void wxTaskBarIcon::RegisterWindowMessages()
269 {
270 static bool s_registered = false;
271
272 if ( !s_registered )
273 {
274 // Taskbar restart msg will be sent to us if the icon needs to be redrawn
275 gs_msgRestartTaskbar = RegisterWindowMessage(wxT("TaskbarCreated"));
276
277 // Also register the taskbar message here
278 gs_msgTaskbar = ::RegisterWindowMessage(wxT("wxTaskBarIconMessage"));
279
280 s_registered = true;
281 }
282 }
283
284 // ----------------------------------------------------------------------------
285 // wxTaskBarIcon window proc
286 // ----------------------------------------------------------------------------
287
288 long wxTaskBarIcon::WindowProc(unsigned int msg,
289 unsigned int WXUNUSED(wParam),
290 long lParam)
291 {
292 wxEventType eventType = 0;
293
294 if (msg == gs_msgRestartTaskbar) // does the icon need to be redrawn?
295 {
296 m_iconAdded = false;
297 SetIcon(m_icon, m_strTooltip);
298 return 0;
299 }
300
301 // this function should only be called for gs_msg(Restart)Taskbar messages
302 wxASSERT(msg == gs_msgTaskbar);
303
304 switch (lParam)
305 {
306 case WM_LBUTTONDOWN:
307 eventType = wxEVT_TASKBAR_LEFT_DOWN;
308 break;
309
310 case WM_LBUTTONUP:
311 eventType = wxEVT_TASKBAR_LEFT_UP;
312 break;
313
314 case WM_RBUTTONDOWN:
315 eventType = wxEVT_TASKBAR_RIGHT_DOWN;
316 break;
317
318 case WM_RBUTTONUP:
319 eventType = wxEVT_TASKBAR_RIGHT_UP;
320 break;
321
322 case WM_LBUTTONDBLCLK:
323 eventType = wxEVT_TASKBAR_LEFT_DCLICK;
324 break;
325
326 case WM_RBUTTONDBLCLK:
327 eventType = wxEVT_TASKBAR_RIGHT_DCLICK;
328 break;
329
330 case WM_MOUSEMOVE:
331 eventType = wxEVT_TASKBAR_MOVE;
332 break;
333
334 default:
335 break;
336 }
337
338 if (eventType)
339 {
340 wxTaskBarIconEvent event(eventType, this);
341
342 ProcessEvent(event);
343 }
344
345 return 0;
346 }
347
348 #endif // wxUSE_TASKBARICON
349