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 // initialized on demand
36 UINT gs_msgTaskbar
= 0;
37 UINT gs_msgRestartTaskbar
= 0;
40 IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon
, wxEvtHandler
)
42 // ============================================================================
44 // ============================================================================
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
)
51 #if wxUSE_DYNLIB_CLASS
52 typedef BOOL (WINAPI
*Shell_NotifyIcon_t
)(DWORD
, NOTIFYICONDATA
*);
54 static Shell_NotifyIcon_t s_pfnShell_NotifyIcon
= NULL
;
55 static bool s_initialized
= false;
61 wxDynamicLibrary
dllShell("shell32.dll");
62 if ( dllShell
.IsLoaded() )
64 s_pfnShell_NotifyIcon
=
65 (Shell_NotifyIcon_t
)dllShell
.GetSymbolAorW("Shell_NotifyIcon");
68 // NB: it's ok to destroy dllShell here, we link to shell32.dll
69 // implicitly so it won't be unloaded
72 return s_pfnShell_NotifyIcon
? (*s_pfnShell_NotifyIcon
)(dwMessage
, pData
)
74 #else // !wxUSE_DYNLIB_CLASS
75 return Shell_NotifyIcon(dwMessage
, pData
);
76 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
79 // ----------------------------------------------------------------------------
80 // wxTaskBarIconWindow: helper window
81 // ----------------------------------------------------------------------------
83 // NB: this class serves two purposes:
84 // 1. win32 needs a HWND associated with taskbar icon, this provides it
85 // 2. we need wxTopLevelWindow so that the app doesn't exit when
86 // last frame is closed but there still is a taskbar icon
87 class wxTaskBarIconWindow
: public wxFrame
90 wxTaskBarIconWindow(wxTaskBarIcon
*icon
)
91 : wxFrame(NULL
, wxID_ANY
, wxEmptyString
, wxDefaultPosition
, wxDefaultSize
, 0),
96 WXLRESULT
MSWWindowProc(WXUINT msg
,
97 WXWPARAM wParam
, WXLPARAM lParam
)
99 if (msg
== gs_msgRestartTaskbar
|| msg
== gs_msgTaskbar
)
101 return m_icon
->WindowProc(msg
, wParam
, lParam
);
105 return wxFrame::MSWWindowProc(msg
, wParam
, lParam
);
110 wxTaskBarIcon
*m_icon
;
114 // ----------------------------------------------------------------------------
115 // NotifyIconData: wrapper around NOTIFYICONDATA
116 // ----------------------------------------------------------------------------
118 struct NotifyIconData
: public NOTIFYICONDATA
120 NotifyIconData(WXHWND hwnd
)
122 memset(this, 0, sizeof(NOTIFYICONDATA
));
123 cbSize
= sizeof(NOTIFYICONDATA
);
125 uCallbackMessage
= gs_msgTaskbar
;
126 uFlags
= NIF_MESSAGE
;
128 // we use the same id for all taskbar icons as we don't need it to
129 // distinguish between them
134 // ----------------------------------------------------------------------------
136 // ----------------------------------------------------------------------------
138 wxTaskBarIcon::wxTaskBarIcon()
142 RegisterWindowMessages();
145 wxTaskBarIcon::~wxTaskBarIcon()
155 bool wxTaskBarIcon::SetIcon(const wxIcon
& icon
, const wxString
& tooltip
)
157 // NB: we have to create the window lazily because of backward compatibility,
158 // old applications may create a wxTaskBarIcon instance before wxApp
159 // is initialized (as samples/taskbar used to do)
162 m_win
= new wxTaskBarIconWindow(this);
166 m_strTooltip
= tooltip
;
168 NotifyIconData
notifyData(GetHwndOf(m_win
));
172 notifyData
.uFlags
|= NIF_ICON
;
173 notifyData
.hIcon
= GetHiconOf(icon
);
176 // set NIF_TIP even for an empty tooltip: otherwise it would be impossible
177 // to remove an existing tooltip using this function
178 notifyData
.uFlags
|= NIF_TIP
;
179 if ( !tooltip
.empty() )
181 wxStrncpy(notifyData
.szTip
, tooltip
.c_str(), WXSIZEOF(notifyData
.szTip
));
184 bool ok
= wxShellNotifyIcon(m_iconAdded
? NIM_MODIFY
185 : NIM_ADD
, ¬ifyData
) != 0;
187 if ( !m_iconAdded
&& ok
)
193 bool wxTaskBarIcon::RemoveIcon()
200 NotifyIconData
notifyData(GetHwndOf(m_win
));
202 return wxShellNotifyIcon(NIM_DELETE
, ¬ifyData
) != 0;
206 bool wxTaskBarIcon::PopupMenu(wxMenu
*menu
)
208 wxASSERT_MSG( m_win
!= NULL
, _T("taskbar icon not initialized") );
210 static bool s_inPopup
= false;
218 wxGetMousePosition(&x
, &y
);
222 m_win
->PushEventHandler(this);
226 // the SetForegroundWindow() and PostMessage() calls are needed to work
227 // around Win32 bug with the popup menus shown for the notifications as
228 // documented at http://support.microsoft.com/kb/q135788/
229 ::SetForegroundWindow(GetHwndOf(m_win
));
231 bool rval
= m_win
->PopupMenu(menu
, 0, 0);
233 ::PostMessage(GetHwndOf(m_win
), WM_NULL
, 0, 0L);
235 m_win
->PopEventHandler(false);
241 #endif // wxUSE_MENUS
243 void wxTaskBarIcon::RegisterWindowMessages()
245 static bool s_registered
= false;
249 // Taskbar restart msg will be sent to us if the icon needs to be redrawn
250 gs_msgRestartTaskbar
= RegisterWindowMessage(wxT("TaskbarCreated"));
252 // Also register the taskbar message here
253 gs_msgTaskbar
= ::RegisterWindowMessage(wxT("wxTaskBarIconMessage"));
259 // ----------------------------------------------------------------------------
260 // wxTaskBarIcon window proc
261 // ----------------------------------------------------------------------------
263 long wxTaskBarIcon::WindowProc(unsigned int msg
,
264 unsigned int WXUNUSED(wParam
),
267 wxEventType eventType
= 0;
269 if (msg
== gs_msgRestartTaskbar
) // does the icon need to be redrawn?
272 SetIcon(m_icon
, m_strTooltip
);
275 // this function should only be called for gs_msg(Restart)Taskbar messages
276 wxASSERT(msg
== gs_msgTaskbar
);
281 eventType
= wxEVT_TASKBAR_LEFT_DOWN
;
285 eventType
= wxEVT_TASKBAR_LEFT_UP
;
289 eventType
= wxEVT_TASKBAR_RIGHT_DOWN
;
293 eventType
= wxEVT_TASKBAR_RIGHT_UP
;
296 case WM_LBUTTONDBLCLK
:
297 eventType
= wxEVT_TASKBAR_LEFT_DCLICK
;
300 case WM_RBUTTONDBLCLK
:
301 eventType
= wxEVT_TASKBAR_RIGHT_DCLICK
;
305 eventType
= wxEVT_TASKBAR_MOVE
;
314 wxTaskBarIconEvent
event(eventType
, this);
322 #endif // wxUSE_TASKBARICON