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: taskbar.cpp 50294 2007-11-28 01:59:59Z VZ $ 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#ifndef WX_PRECOMP 21 #include "wx/window.h" 22 #include "wx/frame.h" 23 #include "wx/utils.h" 24 #include "wx/menu.h" 25#endif 26 27#include "wx/msw/private.h" 28#include "wx/msw/winundef.h" 29 30#include <string.h> 31#include "wx/taskbar.h" 32 33#ifdef __WXWINCE__ 34 #include <winreg.h> 35 #include <shellapi.h> 36#endif 37 38// initialized on demand 39UINT gs_msgTaskbar = 0; 40UINT gs_msgRestartTaskbar = 0; 41 42#if WXWIN_COMPATIBILITY_2_4 43BEGIN_EVENT_TABLE(wxTaskBarIcon, wxTaskBarIconBase) 44 EVT_TASKBAR_MOVE (wxTaskBarIcon::_OnMouseMove) 45 EVT_TASKBAR_LEFT_DOWN (wxTaskBarIcon::_OnLButtonDown) 46 EVT_TASKBAR_LEFT_UP (wxTaskBarIcon::_OnLButtonUp) 47 EVT_TASKBAR_RIGHT_DOWN (wxTaskBarIcon::_OnRButtonDown) 48 EVT_TASKBAR_RIGHT_UP (wxTaskBarIcon::_OnRButtonUp) 49 EVT_TASKBAR_LEFT_DCLICK (wxTaskBarIcon::_OnLButtonDClick) 50 EVT_TASKBAR_RIGHT_DCLICK (wxTaskBarIcon::_OnRButtonDClick) 51END_EVENT_TABLE() 52#endif 53 54 55IMPLEMENT_DYNAMIC_CLASS(wxTaskBarIcon, wxEvtHandler) 56 57// ============================================================================ 58// implementation 59// ============================================================================ 60 61// ---------------------------------------------------------------------------- 62// wxTaskBarIconWindow: helper window 63// ---------------------------------------------------------------------------- 64 65// NB: this class serves two purposes: 66// 1. win32 needs a HWND associated with taskbar icon, this provides it 67// 2. we need wxTopLevelWindow so that the app doesn't exit when 68// last frame is closed but there still is a taskbar icon 69class wxTaskBarIconWindow : public wxFrame 70{ 71public: 72 wxTaskBarIconWindow(wxTaskBarIcon *icon) 73 : wxFrame(NULL, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0), 74 m_icon(icon) 75 { 76 } 77 78 WXLRESULT MSWWindowProc(WXUINT msg, 79 WXWPARAM wParam, WXLPARAM lParam) 80 { 81 if (msg == gs_msgRestartTaskbar || msg == gs_msgTaskbar) 82 { 83 return m_icon->WindowProc(msg, wParam, lParam); 84 } 85 else 86 { 87 return wxFrame::MSWWindowProc(msg, wParam, lParam); 88 } 89 } 90 91private: 92 wxTaskBarIcon *m_icon; 93}; 94 95 96// ---------------------------------------------------------------------------- 97// NotifyIconData: wrapper around NOTIFYICONDATA 98// ---------------------------------------------------------------------------- 99 100struct NotifyIconData : public NOTIFYICONDATA 101{ 102 NotifyIconData(WXHWND hwnd) 103 { 104 memset(this, 0, sizeof(NOTIFYICONDATA)); 105 cbSize = sizeof(NOTIFYICONDATA); 106 hWnd = (HWND) hwnd; 107 uCallbackMessage = gs_msgTaskbar; 108 uFlags = NIF_MESSAGE; 109 110 // we use the same id for all taskbar icons as we don't need it to 111 // distinguish between them 112 uID = 99; 113 } 114}; 115 116// ---------------------------------------------------------------------------- 117// wxTaskBarIcon 118// ---------------------------------------------------------------------------- 119 120wxTaskBarIcon::wxTaskBarIcon() 121{ 122 m_win = NULL; 123 m_iconAdded = false; 124 RegisterWindowMessages(); 125} 126 127wxTaskBarIcon::~wxTaskBarIcon() 128{ 129 if (m_iconAdded) 130 RemoveIcon(); 131 132 if (m_win) 133 m_win->Destroy(); 134} 135 136// Operations 137bool wxTaskBarIcon::SetIcon(const wxIcon& icon, const wxString& tooltip) 138{ 139 // NB: we have to create the window lazily because of backward compatibility, 140 // old applications may create a wxTaskBarIcon instance before wxApp 141 // is initialized (as samples/taskbar used to do) 142 if (!m_win) 143 { 144 m_win = new wxTaskBarIconWindow(this); 145 } 146 147 m_icon = icon; 148 m_strTooltip = tooltip; 149 150 NotifyIconData notifyData(GetHwndOf(m_win)); 151 152 if (icon.Ok()) 153 { 154 notifyData.uFlags |= NIF_ICON; 155 notifyData.hIcon = GetHiconOf(icon); 156 } 157 158 // set NIF_TIP even for an empty tooltip: otherwise it would be impossible 159 // to remove an existing tooltip using this function 160 notifyData.uFlags |= NIF_TIP; 161 if ( !tooltip.empty() ) 162 { 163 wxStrncpy(notifyData.szTip, tooltip.c_str(), WXSIZEOF(notifyData.szTip)); 164 } 165 166 bool ok = Shell_NotifyIcon(m_iconAdded ? NIM_MODIFY 167 : NIM_ADD, ¬ifyData) != 0; 168 169 if ( !m_iconAdded && ok ) 170 m_iconAdded = true; 171 172 return ok; 173} 174 175bool wxTaskBarIcon::RemoveIcon() 176{ 177 if (!m_iconAdded) 178 return false; 179 180 m_iconAdded = false; 181 182 NotifyIconData notifyData(GetHwndOf(m_win)); 183 184 return Shell_NotifyIcon(NIM_DELETE, ¬ifyData) != 0; 185} 186 187bool wxTaskBarIcon::PopupMenu(wxMenu *menu) 188{ 189 wxASSERT_MSG( m_win != NULL, _T("taskbar icon not initialized") ); 190 191 static bool s_inPopup = false; 192 193 if (s_inPopup) 194 return false; 195 196 s_inPopup = true; 197 198 int x, y; 199 wxGetMousePosition(&x, &y); 200 201 m_win->Move(x, y); 202 203 m_win->PushEventHandler(this); 204 205 menu->UpdateUI(); 206 207 // the SetForegroundWindow() and PostMessage() calls are needed to work 208 // around Win32 bug with the popup menus shown for the notifications as 209 // documented at http://support.microsoft.com/kb/q135788/ 210 ::SetForegroundWindow(GetHwndOf(m_win)); 211 212 bool rval = m_win->PopupMenu(menu, 0, 0); 213 214 ::PostMessage(GetHwndOf(m_win), WM_NULL, 0, 0L); 215 216 m_win->PopEventHandler(false); 217 218 s_inPopup = false; 219 220 return rval; 221} 222 223#if WXWIN_COMPATIBILITY_2_4 224// Overridables 225void wxTaskBarIcon::OnMouseMove(wxEvent& e) { e.Skip(); } 226void wxTaskBarIcon::OnLButtonDown(wxEvent& e) { e.Skip(); } 227void wxTaskBarIcon::OnLButtonUp(wxEvent& e) { e.Skip(); } 228void wxTaskBarIcon::OnRButtonDown(wxEvent& e) { e.Skip(); } 229void wxTaskBarIcon::OnRButtonUp(wxEvent& e) { e.Skip(); } 230void wxTaskBarIcon::OnLButtonDClick(wxEvent& e) { e.Skip(); } 231void wxTaskBarIcon::OnRButtonDClick(wxEvent& e) { e.Skip(); } 232 233void wxTaskBarIcon::_OnMouseMove(wxTaskBarIconEvent& e) 234 { OnMouseMove(e); } 235void wxTaskBarIcon::_OnLButtonDown(wxTaskBarIconEvent& e) 236 { OnLButtonDown(e); } 237void wxTaskBarIcon::_OnLButtonUp(wxTaskBarIconEvent& e) 238 { OnLButtonUp(e); } 239void wxTaskBarIcon::_OnRButtonDown(wxTaskBarIconEvent& e) 240 { OnRButtonDown(e); } 241void wxTaskBarIcon::_OnRButtonUp(wxTaskBarIconEvent& e) 242 { OnRButtonUp(e); } 243void wxTaskBarIcon::_OnLButtonDClick(wxTaskBarIconEvent& e) 244 { OnLButtonDClick(e); } 245void wxTaskBarIcon::_OnRButtonDClick(wxTaskBarIconEvent& e) 246 { OnRButtonDClick(e); } 247#endif 248 249void wxTaskBarIcon::RegisterWindowMessages() 250{ 251 static bool s_registered = false; 252 253 if ( !s_registered ) 254 { 255 // Taskbar restart msg will be sent to us if the icon needs to be redrawn 256 gs_msgRestartTaskbar = RegisterWindowMessage(wxT("TaskbarCreated")); 257 258 // Also register the taskbar message here 259 gs_msgTaskbar = ::RegisterWindowMessage(wxT("wxTaskBarIconMessage")); 260 261 s_registered = true; 262 } 263} 264 265// ---------------------------------------------------------------------------- 266// wxTaskBarIcon window proc 267// ---------------------------------------------------------------------------- 268 269long wxTaskBarIcon::WindowProc(unsigned int msg, 270 unsigned int WXUNUSED(wParam), 271 long lParam) 272{ 273 wxEventType eventType = 0; 274 275 if (msg == gs_msgRestartTaskbar) // does the icon need to be redrawn? 276 { 277 m_iconAdded = false; 278 SetIcon(m_icon, m_strTooltip); 279 return 0; 280 } 281 282 // this function should only be called for gs_msg(Restart)Taskbar messages 283 wxASSERT(msg == gs_msgTaskbar); 284 285 switch (lParam) 286 { 287 case WM_LBUTTONDOWN: 288 eventType = wxEVT_TASKBAR_LEFT_DOWN; 289 break; 290 291 case WM_LBUTTONUP: 292 eventType = wxEVT_TASKBAR_LEFT_UP; 293 break; 294 295 case WM_RBUTTONDOWN: 296 eventType = wxEVT_TASKBAR_RIGHT_DOWN; 297 break; 298 299 case WM_RBUTTONUP: 300 eventType = wxEVT_TASKBAR_RIGHT_UP; 301 break; 302 303 case WM_LBUTTONDBLCLK: 304 eventType = wxEVT_TASKBAR_LEFT_DCLICK; 305 break; 306 307 case WM_RBUTTONDBLCLK: 308 eventType = wxEVT_TASKBAR_RIGHT_DCLICK; 309 break; 310 311 case WM_MOUSEMOVE: 312 eventType = wxEVT_TASKBAR_MOVE; 313 break; 314 315 default: 316 break; 317 } 318 319 if (eventType) 320 { 321 wxTaskBarIconEvent event(eventType, this); 322 323 ProcessEvent(event); 324 } 325 326 return 0; 327} 328