]> git.saurik.com Git - wxWidgets.git/blob - src/msw/taskbar.cpp
wxXmlNode::GetAttribute's pointer argument must not be NULL, check for it
[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.c_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 wxTaskBarIcon::RemoveIcon()
193 {
194 if (!m_iconAdded)
195 return false;
196
197 m_iconAdded = false;
198
199 NotifyIconData notifyData(GetHwndOf(m_win));
200
201 return wxShellNotifyIcon(NIM_DELETE, &notifyData) != 0;
202 }
203
204 #if wxUSE_MENUS
205 bool wxTaskBarIcon::PopupMenu(wxMenu *menu)
206 {
207 wxASSERT_MSG( m_win != NULL, _T("taskbar icon not initialized") );
208
209 static bool s_inPopup = false;
210
211 if (s_inPopup)
212 return false;
213
214 s_inPopup = true;
215
216 int x, y;
217 wxGetMousePosition(&x, &y);
218
219 m_win->Move(x, y);
220
221 m_win->PushEventHandler(this);
222
223 menu->UpdateUI();
224
225 // the SetForegroundWindow() and PostMessage() calls are needed to work
226 // around Win32 bug with the popup menus shown for the notifications as
227 // documented at http://support.microsoft.com/kb/q135788/
228 ::SetForegroundWindow(GetHwndOf(m_win));
229
230 bool rval = m_win->PopupMenu(menu, 0, 0);
231
232 ::PostMessage(GetHwndOf(m_win), WM_NULL, 0, 0L);
233
234 m_win->PopEventHandler(false);
235
236 s_inPopup = false;
237
238 return rval;
239 }
240 #endif // wxUSE_MENUS
241
242 void wxTaskBarIcon::RegisterWindowMessages()
243 {
244 static bool s_registered = false;
245
246 if ( !s_registered )
247 {
248 // Taskbar restart msg will be sent to us if the icon needs to be redrawn
249 gs_msgRestartTaskbar = RegisterWindowMessage(wxT("TaskbarCreated"));
250
251 // Also register the taskbar message here
252 gs_msgTaskbar = ::RegisterWindowMessage(wxT("wxTaskBarIconMessage"));
253
254 s_registered = true;
255 }
256 }
257
258 // ----------------------------------------------------------------------------
259 // wxTaskBarIcon window proc
260 // ----------------------------------------------------------------------------
261
262 long wxTaskBarIcon::WindowProc(unsigned int msg,
263 unsigned int WXUNUSED(wParam),
264 long lParam)
265 {
266 wxEventType eventType = 0;
267
268 if (msg == gs_msgRestartTaskbar) // does the icon need to be redrawn?
269 {
270 m_iconAdded = false;
271 SetIcon(m_icon, m_strTooltip);
272 }
273
274 // this function should only be called for gs_msg(Restart)Taskbar messages
275 wxASSERT(msg == gs_msgTaskbar);
276
277 switch (lParam)
278 {
279 case WM_LBUTTONDOWN:
280 eventType = wxEVT_TASKBAR_LEFT_DOWN;
281 break;
282
283 case WM_LBUTTONUP:
284 eventType = wxEVT_TASKBAR_LEFT_UP;
285 break;
286
287 case WM_RBUTTONDOWN:
288 eventType = wxEVT_TASKBAR_RIGHT_DOWN;
289 break;
290
291 case WM_RBUTTONUP:
292 eventType = wxEVT_TASKBAR_RIGHT_UP;
293 break;
294
295 case WM_LBUTTONDBLCLK:
296 eventType = wxEVT_TASKBAR_LEFT_DCLICK;
297 break;
298
299 case WM_RBUTTONDBLCLK:
300 eventType = wxEVT_TASKBAR_RIGHT_DCLICK;
301 break;
302
303 case WM_MOUSEMOVE:
304 eventType = wxEVT_TASKBAR_MOVE;
305 break;
306
307 default:
308 break;
309 }
310
311 if (eventType)
312 {
313 wxTaskBarIconEvent event(eventType, this);
314
315 ProcessEvent(event);
316 }
317
318 return 0;
319 }
320
321 #endif // wxUSE_TASKBARICON
322