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
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////
13 // For compilers that support precompilation, includes "wx.h".
14 #include "wx/wxprec.h"
23 #include "wx/window.h"
29 #include "wx/msw/wrapshl.h"
32 #include "wx/taskbar.h"
33 #include "wx/dynlib.h"
35 #ifndef NIN_BALLOONTIMEOUT
36 #define NIN_BALLOONTIMEOUT 0x0404
37 #define NIN_BALLOONUSERCLICK 0x0405
40 // initialized on demand
41 static UINT gs_msgTaskbar
= 0;
42 static UINT gs_msgRestartTaskbar
= 0;
45 IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon
, wxEvtHandler
)
47 // ============================================================================
49 // ============================================================================
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
54 static BOOL
wxShellNotifyIcon(DWORD dwMessage
, NOTIFYICONDATA
*pData
)
56 #if wxUSE_DYNLIB_CLASS
57 typedef BOOL (WINAPI
*Shell_NotifyIcon_t
)(DWORD
, NOTIFYICONDATA
*);
59 static Shell_NotifyIcon_t s_pfnShell_NotifyIcon
= NULL
;
60 static bool s_initialized
= false;
66 wxDynamicLibrary
dllShell("shell32.dll");
67 if ( dllShell
.IsLoaded() )
69 wxDL_INIT_FUNC_AW(s_pfn
, Shell_NotifyIcon
, dllShell
);
72 // NB: it's ok to destroy dllShell here, we link to shell32.dll
73 // implicitly so it won't be unloaded
76 return s_pfnShell_NotifyIcon
? (*s_pfnShell_NotifyIcon
)(dwMessage
, pData
)
78 #else // !wxUSE_DYNLIB_CLASS
79 return Shell_NotifyIcon(dwMessage
, pData
);
80 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
83 // ----------------------------------------------------------------------------
84 // wxTaskBarIconWindow: helper window
85 // ----------------------------------------------------------------------------
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
91 class wxTaskBarIconWindow
: public wxFrame
94 wxTaskBarIconWindow(wxTaskBarIcon
*icon
)
95 : wxFrame(NULL
, wxID_ANY
, wxEmptyString
, wxDefaultPosition
, wxDefaultSize
, 0),
100 WXLRESULT
MSWWindowProc(WXUINT msg
,
101 WXWPARAM wParam
, WXLPARAM lParam
)
103 if (msg
== gs_msgRestartTaskbar
|| msg
== gs_msgTaskbar
)
105 return m_icon
->WindowProc(msg
, wParam
, lParam
);
109 return wxFrame::MSWWindowProc(msg
, wParam
, lParam
);
114 wxTaskBarIcon
*m_icon
;
118 // ----------------------------------------------------------------------------
119 // NotifyIconData: wrapper around NOTIFYICONDATA
120 // ----------------------------------------------------------------------------
122 struct NotifyIconData
: public NOTIFYICONDATA
124 NotifyIconData(WXHWND hwnd
)
126 memset(this, 0, sizeof(NOTIFYICONDATA
));
127 cbSize
= sizeof(NOTIFYICONDATA
);
129 uCallbackMessage
= gs_msgTaskbar
;
130 uFlags
= NIF_MESSAGE
;
132 // we use the same id for all taskbar icons as we don't need it to
133 // distinguish between them
138 // ----------------------------------------------------------------------------
140 // ----------------------------------------------------------------------------
142 wxTaskBarIcon::wxTaskBarIcon()
146 RegisterWindowMessages();
149 wxTaskBarIcon::~wxTaskBarIcon()
159 bool wxTaskBarIcon::SetIcon(const wxIcon
& icon
, const wxString
& tooltip
)
161 // NB: we have to create the window lazily because of backward compatibility,
162 // old applications may create a wxTaskBarIcon instance before wxApp
163 // is initialized (as samples/taskbar used to do)
166 m_win
= new wxTaskBarIconWindow(this);
170 m_strTooltip
= tooltip
;
172 NotifyIconData
notifyData(GetHwndOf(m_win
));
176 notifyData
.uFlags
|= NIF_ICON
;
177 notifyData
.hIcon
= GetHiconOf(icon
);
180 // set NIF_TIP even for an empty tooltip: otherwise it would be impossible
181 // to remove an existing tooltip using this function
182 notifyData
.uFlags
|= NIF_TIP
;
183 if ( !tooltip
.empty() )
185 wxStrncpy(notifyData
.szTip
, tooltip
.wx_str(), WXSIZEOF(notifyData
.szTip
));
188 bool ok
= wxShellNotifyIcon(m_iconAdded
? NIM_MODIFY
189 : NIM_ADD
, ¬ifyData
) != 0;
191 if ( !m_iconAdded
&& ok
)
198 wxTaskBarIcon::ShowBalloon(const wxString
& title
,
199 const wxString
& text
,
203 wxCHECK_MSG( m_iconAdded
, false,
204 _T("can't be used before the icon is created") );
206 const HWND hwnd
= GetHwndOf(m_win
);
208 // we need to enable version 5.0 behaviour to receive notifications about
209 // the balloon disappearance
210 NotifyIconData
notifyData(hwnd
);
211 notifyData
.uFlags
= 0;
212 notifyData
.uVersion
= 3 /* NOTIFYICON_VERSION for Windows XP */;
214 wxShellNotifyIcon(NIM_SETVERSION
, ¬ifyData
);
217 // do show the balloon now
218 notifyData
= NotifyIconData(hwnd
);
219 notifyData
.uFlags
|= NIF_INFO
;
220 notifyData
.uTimeout
= msec
;
221 wxStrncpy(notifyData
.szInfo
, text
.wx_str(), WXSIZEOF(notifyData
.szInfo
));
222 wxStrncpy(notifyData
.szInfoTitle
, title
.wx_str(),
223 WXSIZEOF(notifyData
.szInfoTitle
));
225 if ( flags
& wxICON_INFORMATION
)
226 notifyData
.dwInfoFlags
|= NIIF_INFO
;
227 else if ( flags
& wxICON_WARNING
)
228 notifyData
.dwInfoFlags
|= NIIF_WARNING
;
229 else if ( flags
& wxICON_ERROR
)
230 notifyData
.dwInfoFlags
|= NIIF_ERROR
;
232 return wxShellNotifyIcon(NIM_MODIFY
, ¬ifyData
) != 0;
235 bool wxTaskBarIcon::RemoveIcon()
242 NotifyIconData
notifyData(GetHwndOf(m_win
));
244 return wxShellNotifyIcon(NIM_DELETE
, ¬ifyData
) != 0;
248 bool wxTaskBarIcon::PopupMenu(wxMenu
*menu
)
250 wxASSERT_MSG( m_win
!= NULL
, _T("taskbar icon not initialized") );
252 static bool s_inPopup
= false;
260 wxGetMousePosition(&x
, &y
);
264 m_win
->PushEventHandler(this);
268 // the SetForegroundWindow() and PostMessage() calls are needed to work
269 // around Win32 bug with the popup menus shown for the notifications as
270 // documented at http://support.microsoft.com/kb/q135788/
271 ::SetForegroundWindow(GetHwndOf(m_win
));
273 bool rval
= m_win
->PopupMenu(menu
, 0, 0);
275 ::PostMessage(GetHwndOf(m_win
), WM_NULL
, 0, 0L);
277 m_win
->PopEventHandler(false);
283 #endif // wxUSE_MENUS
285 void wxTaskBarIcon::RegisterWindowMessages()
287 static bool s_registered
= false;
291 // Taskbar restart msg will be sent to us if the icon needs to be redrawn
292 gs_msgRestartTaskbar
= RegisterWindowMessage(wxT("TaskbarCreated"));
294 // Also register the taskbar message here
295 gs_msgTaskbar
= ::RegisterWindowMessage(wxT("wxTaskBarIconMessage"));
301 // ----------------------------------------------------------------------------
302 // wxTaskBarIcon window proc
303 // ----------------------------------------------------------------------------
305 long wxTaskBarIcon::WindowProc(unsigned int msg
,
306 unsigned int WXUNUSED(wParam
),
309 if ( msg
== gs_msgRestartTaskbar
) // does the icon need to be redrawn?
312 SetIcon(m_icon
, m_strTooltip
);
316 // this function should only be called for gs_msg(Restart)Taskbar messages
317 wxASSERT( msg
== gs_msgTaskbar
);
319 wxEventType eventType
= 0;
323 eventType
= wxEVT_TASKBAR_LEFT_DOWN
;
327 eventType
= wxEVT_TASKBAR_LEFT_UP
;
331 eventType
= wxEVT_TASKBAR_RIGHT_DOWN
;
335 eventType
= wxEVT_TASKBAR_RIGHT_UP
;
338 case WM_LBUTTONDBLCLK
:
339 eventType
= wxEVT_TASKBAR_LEFT_DCLICK
;
342 case WM_RBUTTONDBLCLK
:
343 eventType
= wxEVT_TASKBAR_RIGHT_DCLICK
;
347 eventType
= wxEVT_TASKBAR_MOVE
;
350 case NIN_BALLOONTIMEOUT
:
351 eventType
= wxEVT_TASKBAR_BALLOON_TIMEOUT
;
354 case NIN_BALLOONUSERCLICK
:
355 eventType
= wxEVT_TASKBAR_BALLOON_CLICK
;
361 wxTaskBarIconEvent
event(eventType
, this);
369 #endif // wxUSE_TASKBARICON