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