]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/taskbar.cpp
Fix assorted typos in comments and other non-code.
[wxWidgets.git] / src / msw / taskbar.cpp
... / ...
CommitLineData
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// Copyright: (c)
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16 #pragma hdrstop
17#endif
18
19#if wxUSE_TASKBARICON
20
21#ifndef WX_PRECOMP
22 #include "wx/window.h"
23 #include "wx/frame.h"
24 #include "wx/utils.h"
25 #include "wx/menu.h"
26 #include "wx/app.h"
27#endif
28
29#include "wx/msw/wrapshl.h"
30
31#include <string.h>
32#include "wx/taskbar.h"
33#include "wx/msw/private.h"
34#include "wx/dynlib.h"
35
36#ifndef NIN_BALLOONTIMEOUT
37 #define NIN_BALLOONTIMEOUT 0x0404
38 #define NIN_BALLOONUSERCLICK 0x0405
39#endif
40
41#ifndef NIM_SETVERSION
42 #define NIM_SETVERSION 0x00000004
43#endif
44
45#ifndef NIF_INFO
46 #define NIF_INFO 0x00000010
47#endif
48
49#ifndef NOTIFYICONDATA_V1_SIZE
50 #ifdef UNICODE
51 #define NOTIFYICONDATA_V1_SIZE 0x0098
52 #else
53 #define NOTIFYICONDATA_V1_SIZE 0x0058
54 #endif
55#endif
56
57#ifndef NOTIFYICONDATA_V2_SIZE
58 #ifdef UNICODE
59 #define NOTIFYICONDATA_V2_SIZE 0x03A8
60 #else
61 #define NOTIFYICONDATA_V2_SIZE 0x01E8
62 #endif
63#endif
64
65// initialized on demand
66static UINT gs_msgTaskbar = 0;
67static UINT gs_msgRestartTaskbar = 0;
68
69
70IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler)
71
72// ============================================================================
73// implementation
74// ============================================================================
75
76// wrapper around Shell_NotifyIcon(): this function is not present in Win95
77// shell32.dll so load it dynamically to allow programs using wxTaskBarIcon to
78// start under this OS
79static BOOL wxShellNotifyIcon(DWORD dwMessage, NOTIFYICONDATA *pData)
80{
81#if wxUSE_DYNLIB_CLASS
82 typedef BOOL (WINAPI *Shell_NotifyIcon_t)(DWORD, NOTIFYICONDATA *);
83
84 static Shell_NotifyIcon_t s_pfnShell_NotifyIcon = NULL;
85 static bool s_initialized = false;
86 if ( !s_initialized )
87 {
88 s_initialized = true;
89
90 wxLogNull noLog;
91 wxDynamicLibrary dllShell("shell32.dll");
92 if ( dllShell.IsLoaded() )
93 {
94 wxDL_INIT_FUNC_AW(s_pfn, Shell_NotifyIcon, dllShell);
95 }
96
97 // NB: it's ok to destroy dllShell here, we link to shell32.dll
98 // implicitly so it won't be unloaded
99 }
100
101 return s_pfnShell_NotifyIcon ? (*s_pfnShell_NotifyIcon)(dwMessage, pData)
102 : FALSE;
103#else // !wxUSE_DYNLIB_CLASS
104 return Shell_NotifyIcon(dwMessage, pData);
105#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
106}
107
108// ----------------------------------------------------------------------------
109// wxTaskBarIconWindow: helper window
110// ----------------------------------------------------------------------------
111
112// NB: this class serves two purposes:
113// 1. win32 needs a HWND associated with taskbar icon, this provides it
114// 2. we need wxTopLevelWindow so that the app doesn't exit when
115// last frame is closed but there still is a taskbar icon
116class wxTaskBarIconWindow : public wxFrame
117{
118public:
119 wxTaskBarIconWindow(wxTaskBarIcon *icon)
120 : wxFrame(NULL, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0),
121 m_icon(icon)
122 {
123 }
124
125 WXLRESULT MSWWindowProc(WXUINT msg,
126 WXWPARAM wParam, WXLPARAM lParam)
127 {
128 if (msg == gs_msgRestartTaskbar || msg == gs_msgTaskbar)
129 {
130 return m_icon->WindowProc(msg, wParam, lParam);
131 }
132 else
133 {
134 return wxFrame::MSWWindowProc(msg, wParam, lParam);
135 }
136 }
137
138private:
139 wxTaskBarIcon *m_icon;
140};
141
142
143// ----------------------------------------------------------------------------
144// NotifyIconData: wrapper around NOTIFYICONDATA
145// ----------------------------------------------------------------------------
146
147struct NotifyIconData : public NOTIFYICONDATA
148{
149 NotifyIconData(WXHWND hwnd)
150 {
151 memset(this, 0, sizeof(NOTIFYICONDATA));
152
153 // Do _not_ use sizeof(NOTIFYICONDATA) here, it may be too big if we're
154 // compiled with newer headers but running on an older system and while
155 // we could do complicated tests for the exact system version it's
156 // easier to just use an old size which should be supported everywhere
157 // from Windows 2000 up and which is all we need as we don't use any
158 // newer features so far. But if we're running under a really ancient
159 // system (Win9x), fall back to even smaller size -- then the balloon
160 // related features won't be available but the rest will still work.
161 cbSize = wxTheApp->GetShell32Version() >= 500
162 ? NOTIFYICONDATA_V2_SIZE
163 : NOTIFYICONDATA_V1_SIZE;
164
165 hWnd = (HWND) hwnd;
166 uCallbackMessage = gs_msgTaskbar;
167 uFlags = NIF_MESSAGE;
168
169 // we use the same id for all taskbar icons as we don't need it to
170 // distinguish between them
171 uID = 99;
172 }
173};
174
175// ----------------------------------------------------------------------------
176// wxTaskBarIcon
177// ----------------------------------------------------------------------------
178
179wxTaskBarIcon::wxTaskBarIcon(wxTaskBarIconType WXUNUSED(iconType))
180{
181 m_win = NULL;
182 m_iconAdded = false;
183 RegisterWindowMessages();
184}
185
186wxTaskBarIcon::~wxTaskBarIcon()
187{
188 if ( m_iconAdded )
189 RemoveIcon();
190
191 if ( m_win )
192 {
193 // we must use delete and not Destroy() here because the latter will
194 // only schedule the window to be deleted during the next idle event
195 // processing but we may not get any idle events if there are no other
196 // windows left in the program
197 delete m_win;
198 }
199}
200
201// Operations
202bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip)
203{
204 // NB: we have to create the window lazily because of backward compatibility,
205 // old applications may create a wxTaskBarIcon instance before wxApp
206 // is initialized (as samples/taskbar used to do)
207 if (!m_win)
208 {
209 m_win = new wxTaskBarIconWindow(this);
210 }
211
212 m_icon = icon;
213 m_strTooltip = tooltip;
214
215 NotifyIconData notifyData(GetHwndOf(m_win));
216
217 if (icon.IsOk())
218 {
219 notifyData.uFlags |= NIF_ICON;
220 notifyData.hIcon = GetHiconOf(icon);
221 }
222
223 // set NIF_TIP even for an empty tooltip: otherwise it would be impossible
224 // to remove an existing tooltip using this function
225 notifyData.uFlags |= NIF_TIP;
226 if ( !tooltip.empty() )
227 {
228 wxStrlcpy(notifyData.szTip, tooltip.t_str(), WXSIZEOF(notifyData.szTip));
229 }
230
231 bool ok = wxShellNotifyIcon(m_iconAdded ? NIM_MODIFY
232 : NIM_ADD, &notifyData) != 0;
233
234 if ( !ok )
235 {
236 wxLogLastError(wxT("wxShellNotifyIcon(NIM_MODIFY/ADD)"));
237 }
238
239 if ( !m_iconAdded && ok )
240 m_iconAdded = true;
241
242 return ok;
243}
244
245#if wxUSE_TASKBARICON_BALLOONS
246
247bool
248wxTaskBarIcon::ShowBalloon(const wxString& title,
249 const wxString& text,
250 unsigned msec,
251 int flags)
252{
253 wxCHECK_MSG( m_iconAdded, false,
254 wxT("can't be used before the icon is created") );
255
256 const HWND hwnd = GetHwndOf(m_win);
257
258 // we need to enable version 5.0 behaviour to receive notifications about
259 // the balloon disappearance
260 NotifyIconData notifyData(hwnd);
261 notifyData.uFlags = 0;
262 notifyData.uVersion = 3 /* NOTIFYICON_VERSION for Windows 2000/XP */;
263
264 if ( !wxShellNotifyIcon(NIM_SETVERSION, &notifyData) )
265 {
266 wxLogLastError(wxT("wxShellNotifyIcon(NIM_SETVERSION)"));
267 }
268
269 // do show the balloon now
270 notifyData = NotifyIconData(hwnd);
271 notifyData.uFlags |= NIF_INFO;
272 notifyData.uTimeout = msec;
273 wxStrlcpy(notifyData.szInfo, text.t_str(), WXSIZEOF(notifyData.szInfo));
274 wxStrlcpy(notifyData.szInfoTitle, title.t_str(),
275 WXSIZEOF(notifyData.szInfoTitle));
276
277 if ( flags & wxICON_INFORMATION )
278 notifyData.dwInfoFlags |= NIIF_INFO;
279 else if ( flags & wxICON_WARNING )
280 notifyData.dwInfoFlags |= NIIF_WARNING;
281 else if ( flags & wxICON_ERROR )
282 notifyData.dwInfoFlags |= NIIF_ERROR;
283
284 bool ok = wxShellNotifyIcon(NIM_MODIFY, &notifyData) != 0;
285 if ( !ok )
286 {
287 wxLogLastError(wxT("wxShellNotifyIcon(NIM_MODIFY)"));
288 }
289
290 return ok;
291}
292
293#endif // wxUSE_TASKBARICON_BALLOONS
294
295bool wxTaskBarIcon::RemoveIcon()
296{
297 if (!m_iconAdded)
298 return false;
299
300 m_iconAdded = false;
301
302 NotifyIconData notifyData(GetHwndOf(m_win));
303
304 bool ok = wxShellNotifyIcon(NIM_DELETE, &notifyData) != 0;
305 if ( !ok )
306 {
307 wxLogLastError(wxT("wxShellNotifyIcon(NIM_DELETE)"));
308 }
309
310 return ok;
311}
312
313#if wxUSE_MENUS
314bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
315{
316 wxASSERT_MSG( m_win != NULL, wxT("taskbar icon not initialized") );
317
318 static bool s_inPopup = false;
319
320 if (s_inPopup)
321 return false;
322
323 s_inPopup = true;
324
325 int x, y;
326 wxGetMousePosition(&x, &y);
327
328 m_win->Move(x, y);
329
330 m_win->PushEventHandler(this);
331
332 menu->UpdateUI();
333
334 // the SetForegroundWindow() and PostMessage() calls are needed to work
335 // around Win32 bug with the popup menus shown for the notifications as
336 // documented at http://support.microsoft.com/kb/q135788/
337 ::SetForegroundWindow(GetHwndOf(m_win));
338
339 bool rval = m_win->PopupMenu(menu, 0, 0);
340
341 ::PostMessage(GetHwndOf(m_win), WM_NULL, 0, 0L);
342
343 m_win->PopEventHandler(false);
344
345 s_inPopup = false;
346
347 return rval;
348}
349#endif // wxUSE_MENUS
350
351void wxTaskBarIcon::RegisterWindowMessages()
352{
353 static bool s_registered = false;
354
355 if ( !s_registered )
356 {
357 // Taskbar restart msg will be sent to us if the icon needs to be redrawn
358 gs_msgRestartTaskbar = RegisterWindowMessage(wxT("TaskbarCreated"));
359
360 // Also register the taskbar message here
361 gs_msgTaskbar = ::RegisterWindowMessage(wxT("wxTaskBarIconMessage"));
362
363 s_registered = true;
364 }
365}
366
367// ----------------------------------------------------------------------------
368// wxTaskBarIcon window proc
369// ----------------------------------------------------------------------------
370
371long wxTaskBarIcon::WindowProc(unsigned int msg,
372 unsigned int WXUNUSED(wParam),
373 long lParam)
374{
375 if ( msg == gs_msgRestartTaskbar ) // does the icon need to be redrawn?
376 {
377 m_iconAdded = false;
378 SetIcon(m_icon, m_strTooltip);
379 return 0;
380 }
381
382 // this function should only be called for gs_msg(Restart)Taskbar messages
383 wxASSERT( msg == gs_msgTaskbar );
384
385 wxEventType eventType = 0;
386 switch ( lParam )
387 {
388 case WM_LBUTTONDOWN:
389 eventType = wxEVT_TASKBAR_LEFT_DOWN;
390 break;
391
392 case WM_LBUTTONUP:
393 eventType = wxEVT_TASKBAR_LEFT_UP;
394 break;
395
396 case WM_RBUTTONDOWN:
397 eventType = wxEVT_TASKBAR_RIGHT_DOWN;
398 break;
399
400 case WM_RBUTTONUP:
401 eventType = wxEVT_TASKBAR_RIGHT_UP;
402 break;
403
404 case WM_LBUTTONDBLCLK:
405 eventType = wxEVT_TASKBAR_LEFT_DCLICK;
406 break;
407
408 case WM_RBUTTONDBLCLK:
409 eventType = wxEVT_TASKBAR_RIGHT_DCLICK;
410 break;
411
412 case WM_MOUSEMOVE:
413 eventType = wxEVT_TASKBAR_MOVE;
414 break;
415
416 case NIN_BALLOONTIMEOUT:
417 eventType = wxEVT_TASKBAR_BALLOON_TIMEOUT;
418 break;
419
420 case NIN_BALLOONUSERCLICK:
421 eventType = wxEVT_TASKBAR_BALLOON_CLICK;
422 break;
423 }
424
425 if ( eventType )
426 {
427 wxTaskBarIconEvent event(eventType, this);
428
429 ProcessEvent(event);
430 }
431
432 return 0;
433}
434
435#endif // wxUSE_TASKBARICON
436