]> git.saurik.com Git - wxWidgets.git/blob - src/msw/taskbar.cpp
0736768648dc6d00a0a594679611179129c74b04
[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 const HWND hwnd = GetHwndOf(m_win);
202
203 // we need to enable version 5.0 behaviour to receive notifications about
204 // the balloon disappearance
205 NotifyIconData notifyData(hwnd);
206 notifyData.uFlags = 0;
207 notifyData.uVersion = 3 /* NOTIFYICON_VERSION for Windows XP */;
208
209 wxShellNotifyIcon(NIM_SETVERSION, &notifyData);
210
211
212 // do show the balloon now
213 notifyData = NotifyIconData(hwnd);
214 notifyData.uFlags |= NIF_INFO;
215 notifyData.uTimeout = msec;
216 wxStrncpy(notifyData.szInfo, text.wx_str(), WXSIZEOF(notifyData.szInfo));
217 wxStrncpy(notifyData.szInfoTitle, title.wx_str(),
218 WXSIZEOF(notifyData.szInfoTitle));
219
220 if ( flags & wxICON_INFORMATION )
221 notifyData.dwInfoFlags |= NIIF_INFO;
222 else if ( flags & wxICON_WARNING )
223 notifyData.dwInfoFlags |= NIIF_WARNING;
224 else if ( flags & wxICON_ERROR )
225 notifyData.dwInfoFlags |= NIIF_ERROR;
226
227 return wxShellNotifyIcon(NIM_MODIFY, &notifyData) != 0;
228 }
229
230 bool wxTaskBarIcon::RemoveIcon()
231 {
232 if (!m_iconAdded)
233 return false;
234
235 m_iconAdded = false;
236
237 NotifyIconData notifyData(GetHwndOf(m_win));
238
239 return wxShellNotifyIcon(NIM_DELETE, &notifyData) != 0;
240 }
241
242 #if wxUSE_MENUS
243 bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
244 {
245 wxASSERT_MSG( m_win != NULL, _T("taskbar icon not initialized") );
246
247 static bool s_inPopup = false;
248
249 if (s_inPopup)
250 return false;
251
252 s_inPopup = true;
253
254 int x, y;
255 wxGetMousePosition(&x, &y);
256
257 m_win->Move(x, y);
258
259 m_win->PushEventHandler(this);
260
261 menu->UpdateUI();
262
263 // the SetForegroundWindow() and PostMessage() calls are needed to work
264 // around Win32 bug with the popup menus shown for the notifications as
265 // documented at http://support.microsoft.com/kb/q135788/
266 ::SetForegroundWindow(GetHwndOf(m_win));
267
268 bool rval = m_win->PopupMenu(menu, 0, 0);
269
270 ::PostMessage(GetHwndOf(m_win), WM_NULL, 0, 0L);
271
272 m_win->PopEventHandler(false);
273
274 s_inPopup = false;
275
276 return rval;
277 }
278 #endif // wxUSE_MENUS
279
280 void wxTaskBarIcon::RegisterWindowMessages()
281 {
282 static bool s_registered = false;
283
284 if ( !s_registered )
285 {
286 // Taskbar restart msg will be sent to us if the icon needs to be redrawn
287 gs_msgRestartTaskbar = RegisterWindowMessage(wxT("TaskbarCreated"));
288
289 // Also register the taskbar message here
290 gs_msgTaskbar = ::RegisterWindowMessage(wxT("wxTaskBarIconMessage"));
291
292 s_registered = true;
293 }
294 }
295
296 // ----------------------------------------------------------------------------
297 // wxTaskBarIcon window proc
298 // ----------------------------------------------------------------------------
299
300 long wxTaskBarIcon::WindowProc(unsigned int msg,
301 unsigned int WXUNUSED(wParam),
302 long lParam)
303 {
304 if ( msg == gs_msgRestartTaskbar ) // does the icon need to be redrawn?
305 {
306 m_iconAdded = false;
307 SetIcon(m_icon, m_strTooltip);
308 return 0;
309 }
310
311 // this function should only be called for gs_msg(Restart)Taskbar messages
312 wxASSERT( msg == gs_msgTaskbar );
313
314 wxEventType eventType = 0;
315 switch ( lParam )
316 {
317 case WM_LBUTTONDOWN:
318 eventType = wxEVT_TASKBAR_LEFT_DOWN;
319 break;
320
321 case WM_LBUTTONUP:
322 eventType = wxEVT_TASKBAR_LEFT_UP;
323 break;
324
325 case WM_RBUTTONDOWN:
326 eventType = wxEVT_TASKBAR_RIGHT_DOWN;
327 break;
328
329 case WM_RBUTTONUP:
330 eventType = wxEVT_TASKBAR_RIGHT_UP;
331 break;
332
333 case WM_LBUTTONDBLCLK:
334 eventType = wxEVT_TASKBAR_LEFT_DCLICK;
335 break;
336
337 case WM_RBUTTONDBLCLK:
338 eventType = wxEVT_TASKBAR_RIGHT_DCLICK;
339 break;
340
341 case WM_MOUSEMOVE:
342 eventType = wxEVT_TASKBAR_MOVE;
343 break;
344
345 case NIN_BALLOONTIMEOUT:
346 eventType = wxEVT_TASKBAR_BALLOON_TIMEOUT;
347 break;
348
349 case NIN_BALLOONUSERCLICK:
350 eventType = wxEVT_TASKBAR_BALLOON_CLICK;
351 break;
352 }
353
354 if ( eventType )
355 {
356 wxTaskBarIconEvent event(eventType, this);
357
358 ProcessEvent(event);
359 }
360
361 return 0;
362 }
363
364 #endif // wxUSE_TASKBARICON
365