Changeset 67 for trunk/SystemTray.cpp
- Timestamp:
- 10/18/2007 9:37:01 AM (6 years ago)
- File:
-
- 1 edited
-
trunk/SystemTray.cpp (modified) (24 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/SystemTray.cpp
r3 r67 1 1 ///////////////////////////////////////////////////////////////////////////// 2 2 // SystemTray.cpp : implementation file 3 // 4 // MFC VERSION 3 5 // 4 6 // This is a conglomeration of ideas from the MSJ "Webster" application, … … 23 25 // hIcon, nSystemTrayID); 24 26 // 25 // Written by Chris Maunder (c hrismaunder@codeguru.com)26 // Copyright (c) 1998 .27 // Written by Chris Maunder (cmaunder@mail.com) 28 // Copyright (c) 1998-2003. 27 29 // 28 30 // Updated: 25 Jul 1998 - Added icon animation, and derived class … … 31 33 // Added API to set default menu item. Code provided 32 34 // by Enrico Lelina. 35 // 36 // Updated: 6 June 1999 - SetIcon can now load non-standard sized icons (Chip Calvert) 37 // Added "bHidden" parameter when creating icon 38 // (Thanks to Michael Gombar for these suggestions) 39 // Restricted tooltip text to 64 characters. 40 // 41 // Updated: 9 Nov 1999 - Now works in WindowsCE. 42 // Fix for use in NT services (Thomas Mooney, TeleProc, Inc) 43 // Added W2K stuff by Michael Dunn 44 // 45 // Updated: 1 Jan 2000 - Added tray minimisation stuff. 46 // 47 // Updated: 21 Sep 2000 - Added GetDoWndAnimation - animation only occurs if the system 48 // settings allow it (Matthew Ellis). Updated the GetTrayWndRect 49 // function to include more fallback logic (Matthew Ellis) 50 // NOTE: Signature of GetTrayWndRect has changed! 51 // 52 // Updated: 4 Aug 2003 - Fixed bug that was stopping icon from being recreated when 53 // Explorer crashed 54 // Fixed resource leak in SetIcon 55 // Animate() now checks for empty icon list - Anton Treskunov 56 // Added the virutal CustomizeMenu() method - Anton Treskunov 57 // 33 58 // 34 59 // This code may be used in compiled form in any way you desire. This … … 41 66 // 42 67 // This file is provided "as is" with no expressed or implied warranty. 43 // The author accepts no liability if it causes any damage to your 44 // computer, causes your pet cat to fall ill, increases baldness or 45 // makes you car start emitting strange noises when you start it up. 68 // The author accepts no liability for any damage caused through use. 46 69 // 47 70 // Expect bugs. … … 54 77 55 78 #include "stdafx.h" 56 #include "resource.h"57 79 #include "SystemTray.h" 58 80 … … 63 85 #endif 64 86 87 #ifndef _WIN32_WCE // Use C++ exception handling instead of structured. 88 #undef TRY 89 #undef CATCH 90 #undef END_CATCH 91 #define TRY try 92 #define CATCH(ex_class, ex_object) catch(ex_class* ex_object) 93 #define END_CATCH 94 #endif // _WIN32_WCE 95 96 #ifndef _countof 97 #define _countof(x) ( sizeof(x) / sizeof(x[0]) ) 98 #endif 99 65 100 IMPLEMENT_DYNAMIC(CSystemTray, CWnd) 66 101 67 UINT CSystemTray::m_nIDEvent = 4567; 102 const UINT CSystemTray::m_nTimerID = 4567; 103 UINT CSystemTray::m_nMaxTooltipLength = 128; // This may change... 104 const UINT CSystemTray::m_nTaskbarCreatedMsg = ::RegisterWindowMessage(_T("TaskbarCreated")); 105 CWnd CSystemTray::m_wndInvisible; 68 106 69 107 ///////////////////////////////////////////////////////////////////////////// … … 75 113 } 76 114 77 CSystemTray::CSystemTray(CWnd* pParent, UINT uCallbackMessage, LPCTSTR szToolTip, 78 HICON icon, UINT uID) 115 CSystemTray::CSystemTray(CWnd* pParent, // The window that will recieve tray notifications 116 UINT uCallbackMessage, // the callback message to send to parent 117 LPCTSTR szToolTip, // tray icon tooltip 118 HICON icon, // Handle to icon 119 UINT uID, // Identifier of tray icon 120 BOOL bHidden /*=FALSE*/, // Hidden on creation? 121 LPCTSTR szBalloonTip /*=NULL*/, // Ballon tip (w2k only) 122 LPCTSTR szBalloonTitle /*=NULL*/, // Balloon tip title (w2k) 123 DWORD dwBalloonIcon /*=NIIF_NONE*/,// Ballon tip icon (w2k) 124 UINT uBalloonTimeout /*=10*/) // Balloon timeout (w2k) 79 125 { 80 126 Initialise(); 81 Create(pParent, uCallbackMessage, szToolTip, icon, uID); 127 Create(pParent, uCallbackMessage, szToolTip, icon, uID, bHidden, 128 szBalloonTip, szBalloonTitle, dwBalloonIcon, uBalloonTimeout); 82 129 } 83 130 … … 85 132 { 86 133 memset(&m_tnd, 0, sizeof(m_tnd)); 87 m_bEnabled = FALSE; 88 m_bHidden = FALSE; 134 135 m_bEnabled = FALSE; 136 m_bHidden = TRUE; 137 m_bRemoved = TRUE; 138 139 m_DefaultMenuItemID = 0; 140 m_DefaultMenuItemByPos = TRUE; 141 142 m_bShowIconPending = FALSE; 143 89 144 m_uIDTimer = 0; 90 145 m_hSavedIcon = NULL; 91 m_DefaultMenuItemID = 0; 92 m_DefaultMenuItemByPos = TRUE; 93 } 94 95 #pragma warning(disable : 4706) 146 147 m_pTargetWnd = NULL; 148 m_uCreationFlags = 0; 149 150 #ifdef SYSTEMTRAY_USEW2K 151 OSVERSIONINFO os = { sizeof(os) }; 152 GetVersionEx(&os); 153 m_bWin2K = ( VER_PLATFORM_WIN32_NT == os.dwPlatformId && os.dwMajorVersion >= 5 ); 154 #else 155 m_bWin2K = FALSE; 156 #endif 157 } 158 159 // update by Michael Dunn, November 1999 160 // 161 // New version of Create() that handles new features in Win 2K. 162 // 163 // Changes: 164 // szTip: Same as old, but can be 128 characters instead of 64. 165 // szBalloonTip: Text for a balloon tooltip that is shown when the icon 166 // is first added to the tray. Pass "" if you don't want 167 // a balloon. 168 // szBalloonTitle: Title text for the balloon tooltip. This text is shown 169 // in bold above the szBalloonTip text. Pass "" if you 170 // don't want a title. 171 // dwBalloonIcon: Specifies which icon will appear in the balloon. Legal 172 // values are: 173 // NIIF_NONE: No icon 174 // NIIF_INFO: Information 175 // NIIF_WARNING: Exclamation 176 // NIIF_ERROR: Critical error (red circle with X) 177 // uBalloonTimeout: Number of seconds for the balloon to remain visible. 178 // Must be between 10 and 30 inclusive. 179 96 180 BOOL CSystemTray::Create(CWnd* pParent, UINT uCallbackMessage, LPCTSTR szToolTip, 97 HICON icon, UINT uID, BOOL bInitialShow /*=TRUE*/) 98 { 181 HICON icon, UINT uID, BOOL bHidden /*=FALSE*/, 182 LPCTSTR szBalloonTip /*=NULL*/, 183 LPCTSTR szBalloonTitle /*=NULL*/, 184 DWORD dwBalloonIcon /*=NIIF_NONE*/, 185 UINT uBalloonTimeout /*=10*/) 186 { 187 #ifdef _WIN32_WCE 188 m_bEnabled = TRUE; 189 #else 99 190 // this is only for Windows 95 (or higher) 100 VERIFY(m_bEnabled = ( GetVersion() & 0xff ) >= 4); 101 if (!m_bEnabled) return FALSE; 102 103 // Make sure Notification window is valid (not needed - CJM) 104 // VERIFY(m_bEnabled = (pParent && ::IsWindow(pParent->GetSafeHwnd()))); 105 // if (!m_bEnabled) return FALSE; 191 m_bEnabled = (GetVersion() & 0xff) >= 4; 192 if (!m_bEnabled) 193 { 194 ASSERT(FALSE); 195 return FALSE; 196 } 197 #endif 198 199 m_nMaxTooltipLength = _countof(m_tnd.szTip); 106 200 107 201 // Make sure we avoid conflict with other messages 108 ASSERT(uCallbackMessage >= WM_USER); 109 110 // Tray only supports tooltip text up to 64 characters 111 ASSERT(_tcslen(szToolTip) <= 64); 202 ASSERT(uCallbackMessage >= WM_APP); 203 204 // Tray only supports tooltip text up to m_nMaxTooltipLength) characters 205 ASSERT(AfxIsValidString(szToolTip)); 206 ASSERT(_tcslen(szToolTip) <= m_nMaxTooltipLength); 112 207 113 208 // Create an invisible window 114 CWnd::CreateEx(0, AfxRegisterWndClass(0), _T(""), WS_POPUP, 0,0, 10,10, NULL, 0);209 CWnd::CreateEx(0, AfxRegisterWndClass(0), _T(""), WS_POPUP, 0,0,0,0, NULL, 0); 115 210 116 211 // load up the NOTIFYICONDATA structure … … 121 216 m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; 122 217 m_tnd.uCallbackMessage = uCallbackMessage; 123 _tcsncpy(m_tnd.szTip, szToolTip, 64); 124 125 if (bInitialShow) 126 { 127 // Set the tray icon 128 VERIFY(m_bEnabled = Shell_NotifyIcon(NIM_ADD, &m_tnd)); 129 return m_bEnabled; 130 } 131 else 132 { 133 m_bHidden = TRUE; 134 return TRUE; 135 } 136 } 137 #pragma warning(default : 4706) 218 _tcsncpy(m_tnd.szTip, szToolTip, m_nMaxTooltipLength-1); 219 220 #ifdef SYSTEMTRAY_USEW2K 221 if (m_bWin2K && szBalloonTip) 222 { 223 // The balloon tooltip text can be up to 255 chars long. 224 ASSERT(AfxIsValidString(szBalloonTip)); 225 ASSERT(lstrlen(szBalloonTip) < 256); 226 227 // The balloon title text can be up to 63 chars long. 228 if (szBalloonTitle) 229 { 230 ASSERT(AfxIsValidString(szBalloonTitle)); 231 ASSERT(lstrlen(szBalloonTitle) < 64); 232 } 233 234 // dwBalloonIcon must be valid. 235 ASSERT(NIIF_NONE == dwBalloonIcon || NIIF_INFO == dwBalloonIcon || 236 NIIF_WARNING == dwBalloonIcon || NIIF_ERROR == dwBalloonIcon); 237 238 // The timeout must be between 10 and 30 seconds. 239 ASSERT(uBalloonTimeout >= 10 && uBalloonTimeout <= 30); 240 241 m_tnd.uFlags |= NIF_INFO; 242 243 _tcsncpy(m_tnd.szInfo, szBalloonTip, 255); 244 if (szBalloonTitle) 245 _tcsncpy(m_tnd.szInfoTitle, szBalloonTitle, 63); 246 else 247 m_tnd.szInfoTitle[0] = _T('\0'); 248 m_tnd.uTimeout = uBalloonTimeout * 1000; // convert time to ms 249 m_tnd.dwInfoFlags = dwBalloonIcon; 250 } 251 #endif 252 253 m_bHidden = bHidden; 254 255 #ifdef SYSTEMTRAY_USEW2K 256 if (m_bWin2K && m_bHidden) 257 { 258 m_tnd.uFlags = NIF_STATE; 259 m_tnd.dwState = NIS_HIDDEN; 260 m_tnd.dwStateMask = NIS_HIDDEN; 261 } 262 #endif 263 264 m_uCreationFlags = m_tnd.uFlags; // Store in case we need to recreate in OnTaskBarCreate 265 266 BOOL bResult = TRUE; 267 if (!m_bHidden || m_bWin2K) 268 { 269 bResult = Shell_NotifyIcon(NIM_ADD, &m_tnd); 270 m_bShowIconPending = m_bHidden = m_bRemoved = !bResult; 271 } 272 273 #ifdef SYSTEMTRAY_USEW2K 274 if (m_bWin2K && szBalloonTip) 275 { 276 // Zero out the balloon text string so that later operations won't redisplay 277 // the balloon. 278 m_tnd.szInfo[0] = _T('\0'); 279 } 280 #endif 281 282 return bResult; 283 } 138 284 139 285 CSystemTray::~CSystemTray() … … 147 293 // CSystemTray icon manipulation 148 294 149 void CSystemTray::MoveToRight() 150 { 151 HideIcon(); 152 ShowIcon(); 153 } 154 155 void CSystemTray::RemoveIcon() 156 { 157 if (!m_bEnabled) return; 295 ////////////////////////////////////////////////////////////////////////// 296 // 297 // Function: SetFocus() 298 // 299 // Description: 300 // Sets the focus to the tray icon. Microsoft's Win 2K UI guidelines 301 // say you should do this after the user dismisses the icon's context 302 // menu. 303 // 304 // Input: 305 // Nothing. 306 // 307 // Returns: 308 // Nothing. 309 // 310 ////////////////////////////////////////////////////////////////////////// 311 // Added by Michael Dunn, November, 1999 312 ////////////////////////////////////////////////////////////////////////// 313 314 void CSystemTray::SetFocus() 315 { 316 #ifdef SYSTEMTRAY_USEW2K 317 Shell_NotifyIcon ( NIM_SETFOCUS, &m_tnd ); 318 #endif 319 } 320 321 BOOL CSystemTray::MoveToRight() 322 { 323 RemoveIcon(); 324 return AddIcon(); 325 } 326 327 BOOL CSystemTray::AddIcon() 328 { 329 if (!m_bRemoved) 330 RemoveIcon(); 331 332 if (m_bEnabled) 333 { 334 m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; 335 if (!Shell_NotifyIcon(NIM_ADD, &m_tnd)) 336 m_bShowIconPending = TRUE; 337 else 338 m_bRemoved = m_bHidden = FALSE; 339 } 340 return (m_bRemoved == FALSE); 341 } 342 343 BOOL CSystemTray::RemoveIcon() 344 { 345 m_bShowIconPending = FALSE; 346 347 if (!m_bEnabled || m_bRemoved) 348 return TRUE; 158 349 159 350 m_tnd.uFlags = 0; 160 Shell_NotifyIcon(NIM_DELETE, &m_tnd); 161 m_bEnabled = FALSE; 162 } 163 164 void CSystemTray::HideIcon() 165 { 166 if (m_bEnabled && !m_bHidden) { 167 m_tnd.uFlags = NIF_ICON; 168 Shell_NotifyIcon (NIM_DELETE, &m_tnd); 169 m_bHidden = TRUE; 170 } 171 } 172 173 void CSystemTray::ShowIcon() 174 { 175 if (m_bEnabled && m_bHidden) { 176 m_tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; 177 Shell_NotifyIcon(NIM_ADD, &m_tnd); 351 if (Shell_NotifyIcon(NIM_DELETE, &m_tnd)) 352 m_bRemoved = m_bHidden = TRUE; 353 354 return (m_bRemoved == TRUE); 355 } 356 357 BOOL CSystemTray::HideIcon() 358 { 359 if (!m_bEnabled || m_bRemoved || m_bHidden) 360 return TRUE; 361 362 #ifdef SYSTEMTRAY_USEW2K 363 if (m_bWin2K) 364 { 365 m_tnd.uFlags = NIF_STATE; 366 m_tnd.dwState = NIS_HIDDEN; 367 m_tnd.dwStateMask = NIS_HIDDEN; 368 369 m_bHidden = Shell_NotifyIcon( NIM_MODIFY, &m_tnd); 370 } 371 else 372 #endif 373 RemoveIcon(); 374 375 return (m_bHidden == TRUE); 376 } 377 378 BOOL CSystemTray::ShowIcon() 379 { 380 if (m_bRemoved) 381 return AddIcon(); 382 383 if (!m_bHidden) 384 return TRUE; 385 386 #ifdef SYSTEMTRAY_USEW2K 387 if (m_bWin2K) 388 { 389 m_tnd.uFlags = NIF_STATE; 390 m_tnd.dwState = 0; 391 m_tnd.dwStateMask = NIS_HIDDEN; 392 Shell_NotifyIcon ( NIM_MODIFY, &m_tnd ); 178 393 m_bHidden = FALSE; 179 394 } 395 else 396 #endif 397 AddIcon(); 398 399 return (m_bHidden == FALSE); 180 400 } 181 401 182 402 BOOL CSystemTray::SetIcon(HICON hIcon) 183 403 { 184 if (!m_bEnabled) return FALSE;185 if (m_tnd.hIcon == hIcon) return TRUE;404 if (!m_bEnabled) 405 return FALSE; 186 406 187 407 m_tnd.uFlags = NIF_ICON; 188 408 m_tnd.hIcon = hIcon; 189 409 190 return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); 410 if (m_bHidden) 411 return TRUE; 412 else 413 return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); 191 414 } 192 415 193 416 BOOL CSystemTray::SetIcon(LPCTSTR lpszIconName) 194 417 { 195 HICON hIcon = AfxGetApp()->LoadIcon(lpszIconName); 418 HICON hIcon = (HICON) ::LoadImage(AfxGetResourceHandle(), 419 lpszIconName, 420 IMAGE_ICON, 421 0, 0, 422 LR_DEFAULTCOLOR); 423 if (!hIcon) 424 return FALSE; 425 426 BOOL bSuccess = SetIcon(hIcon); 427 ::DestroyIcon(hIcon); 428 429 return bSuccess; 430 } 431 432 BOOL CSystemTray::SetIcon(UINT nIDResource) 433 { 434 return SetIcon(MAKEINTRESOURCE(nIDResource)); 435 } 436 437 BOOL CSystemTray::SetStandardIcon(LPCTSTR lpIconName) 438 { 439 HICON hIcon = LoadIcon(NULL, lpIconName); 196 440 197 441 return SetIcon(hIcon); 198 442 } 199 443 200 BOOL CSystemTray::SetIcon(UINT nIDResource)201 {202 HICON hIcon = AfxGetApp()->LoadIcon(nIDResource);203 204 return SetIcon(hIcon);205 }206 207 BOOL CSystemTray::SetStandardIcon(LPCTSTR lpIconName)208 {209 HICON hIcon = LoadIcon(NULL, lpIconName);210 211 return SetIcon(hIcon);212 }213 214 444 BOOL CSystemTray::SetStandardIcon(UINT nIDResource) 215 445 { 216 HICON hIcon = LoadIcon(NULL, MAKEINTRESOURCE(nIDResource)); 217 218 return SetIcon(hIcon); 446 return SetStandardIcon(MAKEINTRESOURCE(nIDResource)); 219 447 } 220 448 … … 226 454 BOOL CSystemTray::SetIconList(UINT uFirstIconID, UINT uLastIconID) 227 455 { 228 if (uFirstIconID > uLastIconID) 229 return FALSE; 230 231 // UINT uIconArraySize = uLastIconID - uFirstIconID + 1; 232 const CWinApp * pApp = AfxGetApp(); 233 ASSERT(pApp != 0); 456 if (uFirstIconID > uLastIconID) 457 return FALSE; 458 459 const CWinApp* pApp = AfxGetApp(); 460 if (!pApp) 461 { 462 ASSERT(FALSE); 463 return FALSE; 464 } 234 465 235 466 m_IconList.RemoveAll(); 236 try{237 for (UINT i = uFirstIconID; i <= uLastIconID; i++)238 m_IconList.Add(pApp->LoadIcon(i));239 } 240 catch (CException *e)241 { 242 REPORT_ERROR(e);467 TRY { 468 for (UINT i = uFirstIconID; i <= uLastIconID; i++) 469 m_IconList.Add(pApp->LoadIcon(i)); 470 } 471 CATCH(CMemoryException, e) 472 { 473 e->ReportError(); 243 474 e->Delete(); 244 475 m_IconList.RemoveAll(); 245 476 return FALSE; 246 477 } 478 END_CATCH 247 479 248 480 return TRUE; … … 253 485 m_IconList.RemoveAll(); 254 486 255 try{256 for (UINT i = 0; i <=nNumIcons; i++)257 m_IconList.Add(pHIconList[i]);258 } 259 catch (CException *e)260 { 261 REPORT_ERROR(e);487 TRY { 488 for (UINT i = 0; i < nNumIcons; i++) 489 m_IconList.Add(pHIconList[i]); 490 } 491 CATCH (CMemoryException, e) 492 { 493 e->ReportError(); 262 494 e->Delete(); 263 495 m_IconList.RemoveAll(); 264 496 return FALSE; 265 497 } 498 END_CATCH 266 499 267 500 return TRUE; … … 270 503 BOOL CSystemTray::Animate(UINT nDelayMilliSeconds, int nNumSeconds /*=-1*/) 271 504 { 505 if (m_IconList.IsEmpty()) 506 return FALSE; 507 272 508 StopAnimation(); 273 509 274 510 m_nCurrentIcon = 0; 275 m_StartTime = GetTimeTimeZoneBased();511 m_StartTime = COleDateTime::GetCurrentTime(); 276 512 m_nAnimationPeriod = nNumSeconds; 277 513 m_hSavedIcon = GetIcon(); 278 514 279 // Setup a timer for the animation280 m_uIDTimer = SetTimer(m_nIDEvent, nDelayMilliSeconds, NULL);515 // Setup a timer for the animation 516 m_uIDTimer = SetTimer(m_nTimerID, nDelayMilliSeconds, NULL); 281 517 282 518 return (m_uIDTimer != 0); … … 300 536 301 537 if (m_uIDTimer) 302 bResult = KillTimer(m_uIDTimer);538 bResult = KillTimer(m_uIDTimer); 303 539 m_uIDTimer = 0; 304 540 … … 315 551 BOOL CSystemTray::SetTooltipText(LPCTSTR pszTip) 316 552 { 317 if (!m_bEnabled) return FALSE; 553 ASSERT(AfxIsValidString(pszTip)); // (md) 554 ASSERT(_tcslen(pszTip) < m_nMaxTooltipLength); 555 556 if (!m_bEnabled) 557 return FALSE; 318 558 319 559 m_tnd.uFlags = NIF_TIP; 320 _tcsncpy(m_tnd.szTip, pszTip, 64); 321 322 return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); 560 _tcsncpy(m_tnd.szTip, pszTip, m_nMaxTooltipLength-1); 561 562 if (m_bHidden) 563 return TRUE; 564 else 565 return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); 323 566 } 324 567 … … 326 569 { 327 570 CString strText; 328 329 try 330 { 331 VERIFY(strText.LoadString(nID)); 332 } 333 catch (...) 334 { 335 strText.Empty(); 336 } 571 VERIFY(strText.LoadString(nID)); 337 572 338 573 return SetTooltipText(strText); … … 349 584 350 585 ///////////////////////////////////////////////////////////////////////////// 586 // CSystemTray support for Win 2K features. 587 588 ////////////////////////////////////////////////////////////////////////// 589 // 590 // Function: ShowBalloon 591 // 592 // Description: 593 // Shows a balloon tooltip over the tray icon. 594 // 595 // Input: 596 // szText: [in] Text for the balloon tooltip. 597 // szTitle: [in] Title for the balloon. This text is shown in bold above 598 // the tooltip text (szText). Pass "" if you don't want a title. 599 // dwIcon: [in] Specifies an icon to appear in the balloon. Legal values are: 600 // NIIF_NONE: No icon 601 // NIIF_INFO: Information 602 // NIIF_WARNING: Exclamation 603 // NIIF_ERROR: Critical error (red circle with X) 604 // uTimeout: [in] Number of seconds for the balloon to remain visible. Can 605 // be between 10 and 30 inclusive. 606 // 607 // Returns: 608 // TRUE if successful, FALSE if not. 609 // 610 ////////////////////////////////////////////////////////////////////////// 611 // Added by Michael Dunn, November 1999 612 ////////////////////////////////////////////////////////////////////////// 613 614 BOOL CSystemTray::ShowBalloon(LPCTSTR szText, 615 LPCTSTR szTitle /*=NULL*/, 616 DWORD dwIcon /*=NIIF_NONE*/, 617 UINT uTimeout /*=10*/ ) 618 { 619 #ifndef SYSTEMTRAY_USEW2K 620 return FALSE; 621 #else 622 // Bail out if we're not on Win 2K. 623 if (!m_bWin2K) 624 return FALSE; 625 626 // Verify input parameters. 627 628 // The balloon tooltip text can be up to 255 chars long. 629 ASSERT(AfxIsValidString(szText)); 630 ASSERT(lstrlen(szText) < 256); 631 632 // The balloon title text can be up to 63 chars long. 633 if (szTitle) 634 { 635 ASSERT(AfxIsValidString( szTitle)); 636 ASSERT(lstrlen(szTitle) < 64); 637 } 638 639 // dwBalloonIcon must be valid. 640 ASSERT(NIIF_NONE == dwIcon || NIIF_INFO == dwIcon || 641 NIIF_WARNING == dwIcon || NIIF_ERROR == dwIcon); 642 643 // The timeout must be between 10 and 30 seconds. 644 ASSERT(uTimeout >= 10 && uTimeout <= 30); 645 646 647 m_tnd.uFlags = NIF_INFO; 648 _tcsncpy(m_tnd.szInfo, szText, 256); 649 if (szTitle) 650 _tcsncpy(m_tnd.szInfoTitle, szTitle, 64); 651 else 652 m_tnd.szInfoTitle[0] = _T('\0'); 653 m_tnd.dwInfoFlags = dwIcon; 654 m_tnd.uTimeout = uTimeout * 1000; // convert time to ms 655 656 BOOL bSuccess = Shell_NotifyIcon (NIM_MODIFY, &m_tnd); 657 658 // Zero out the balloon text string so that later operations won't redisplay 659 // the balloon. 660 m_tnd.szInfo[0] = _T('\0'); 661 662 return bSuccess; 663 #endif 664 } 665 666 ///////////////////////////////////////////////////////////////////////////// 351 667 // CSystemTray notification window stuff 352 668 353 669 BOOL CSystemTray::SetNotificationWnd(CWnd* pWnd) 354 670 { 355 if (!m_bEnabled) return FALSE; 671 if (!m_bEnabled) 672 return FALSE; 356 673 357 674 // Make sure Notification window is valid 358 ASSERT(pWnd && ::IsWindow(pWnd->GetSafeHwnd())); 675 if (!pWnd || !::IsWindow(pWnd->GetSafeHwnd())) 676 { 677 ASSERT(FALSE); 678 return FALSE; 679 } 359 680 360 681 m_tnd.hWnd = pWnd->GetSafeHwnd(); 361 682 m_tnd.uFlags = 0; 362 683 363 return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); 684 if (m_bHidden) 685 return TRUE; 686 else 687 return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); 364 688 } 365 689 … … 367 691 { 368 692 return CWnd::FromHandle(m_tnd.hWnd); 693 } 694 695 // Hatr added 696 697 // Hatr added 698 699 // Change or retrive the window to send menu commands to 700 BOOL CSystemTray::SetTargetWnd(CWnd* pTargetWnd) 701 { 702 m_pTargetWnd = pTargetWnd; 703 return TRUE; 704 } // CSystemTray::SetTargetWnd() 705 706 CWnd* CSystemTray::GetTargetWnd() const 707 { 708 if (m_pTargetWnd) 709 return m_pTargetWnd; 710 else 711 return AfxGetMainWnd(); 712 } // CSystemTray::GetTargetWnd() 713 714 ///////////////////////////////////////////////////////////////////////////// 715 // CSystemTray notification message stuff 716 717 BOOL CSystemTray::SetCallbackMessage(UINT uCallbackMessage) 718 { 719 if (!m_bEnabled) 720 return FALSE; 721 722 // Make sure we avoid conflict with other messages 723 ASSERT(uCallbackMessage >= WM_APP); 724 725 m_tnd.uCallbackMessage = uCallbackMessage; 726 m_tnd.uFlags = NIF_MESSAGE; 727 728 if (m_bHidden) 729 return TRUE; 730 else 731 return Shell_NotifyIcon(NIM_MODIFY, &m_tnd); 732 } 733 734 UINT CSystemTray::GetCallbackMessage() const 735 { 736 return m_tnd.uCallbackMessage; 369 737 } 370 738 … … 374 742 BOOL CSystemTray::SetMenuDefaultItem(UINT uItem, BOOL bByPos) 375 743 { 744 #ifdef _WIN32_WCE 745 return FALSE; 746 #else 376 747 if ((m_DefaultMenuItemID == uItem) && (m_DefaultMenuItemByPos == bByPos)) 377 748 return TRUE; … … 382 753 CMenu menu, *pSubMenu; 383 754 384 if (!menu.LoadMenu(m_tnd.uID)) return FALSE; 755 if (!menu.LoadMenu(m_tnd.uID)) 756 return FALSE; 385 757 386 758 pSubMenu = menu.GetSubMenu(0); 387 if (!pSubMenu) return FALSE; 759 if (!pSubMenu) 760 return FALSE; 388 761 389 762 ::SetMenuDefaultItem(pSubMenu->m_hMenu, m_DefaultMenuItemID, m_DefaultMenuItemByPos); 390 763 391 menu.DestroyMenu();392 393 764 return TRUE; 765 #endif 394 766 } 395 767 … … 404 776 405 777 BEGIN_MESSAGE_MAP(CSystemTray, CWnd) 406 //{{AFX_MSG_MAP(CSystemTray) 407 ON_WM_TIMER() 408 //}}AFX_MSG_MAP 778 //{{AFX_MSG_MAP(CSystemTray) 779 ON_WM_TIMER() 780 //}}AFX_MSG_MAP 781 #ifndef _WIN32_WCE 782 ON_WM_SETTINGCHANGE() 783 #endif 784 ON_REGISTERED_MESSAGE(CSystemTray::m_nTaskbarCreatedMsg, OnTaskbarCreated) 409 785 END_MESSAGE_MAP() 410 786 411 787 void CSystemTray::OnTimer(UINT_PTR nIDEvent) 412 788 { 413 UNUSED(nIDEvent); 414 ASSERT(nIDEvent == m_nIDEvent); 415 416 COleDateTime CurrentTime = GetTimeTimeZoneBased(); 789 if (nIDEvent != m_uIDTimer) 790 { 791 ASSERT(FALSE); 792 return; 793 } 794 795 COleDateTime CurrentTime = COleDateTime::GetCurrentTime(); 417 796 COleDateTimeSpan period = CurrentTime - m_StartTime; 797 418 798 if (m_nAnimationPeriod > 0 && m_nAnimationPeriod < period.GetTotalSeconds()) 419 799 { … … 425 805 } 426 806 427 void CSystemTray::DeleteItem(UINT uItem) 428 { 429 m_ItemsToDelete.Add(uItem); 430 } 431 432 void CSystemTray::CheckItem(UINT uItem) 433 { 434 m_ItemsToCheck.Add(uItem); 435 } 436 437 void CSystemTray::DisableItem(UINT uItem) 438 { 439 m_ItemsToDisable.Add(uItem); 440 } 441 442 void CSystemTray::CleanCheckList() 443 { 444 m_ItemsToCheck.RemoveAll(); 445 } 446 447 void CSystemTray::CleanDisableList() 448 { 449 m_ItemsToDisable.RemoveAll(); 450 } 451 452 void CSystemTray::CleanDeleteList() 453 { 454 m_ItemsToDelete.RemoveAll(); 455 } 807 // This is called whenever the taskbar is created (eg after explorer crashes 808 // and restarts. Please note that the WM_TASKBARCREATED message is only passed 809 // to TOP LEVEL windows (like WM_QUERYNEWPALETTE) 810 LRESULT CSystemTray::OnTaskbarCreated(WPARAM /*wParam*/, LPARAM /*lParam*/) 811 { 812 m_bShowIconPending = TRUE; // !m_bHidden; 813 InstallIconPending(); 814 815 return 0L; 816 } 817 818 #ifndef _WIN32_WCE 819 void CSystemTray::OnSettingChange(UINT uFlags, LPCTSTR lpszSection) 820 { 821 CWnd::OnSettingChange(uFlags, lpszSection); 822 823 if (uFlags == SPI_SETWORKAREA) 824 { 825 m_bShowIconPending = !m_bHidden; 826 InstallIconPending(); 827 } 828 } 829 #endif 456 830 457 831 LRESULT CSystemTray::OnTrayNotification(WPARAM wParam, LPARAM lParam) … … 459 833 //Return quickly if its not for this tray icon 460 834 if (wParam != m_tnd.uID) 461 return (0L);835 return 0L; 462 836 463 837 CMenu menu, *pSubMenu; 464 CWnd* pTarget = AfxGetMainWnd(); 465 466 // sanity check - st@iki.fi 467 if (!IsWindow(pTarget->GetSafeHwnd())) 468 return(0); 838 CWnd *pTargetWnd = GetTargetWnd(); 839 if (!pTargetWnd) 840 return 0L; 469 841 470 842 // Clicking with right button brings up a context menu 843 #if defined(_WIN32_WCE) //&& _WIN32_WCE < 211 844 BOOL bAltPressed = ((GetKeyState(VK_MENU) & (1 << (sizeof(SHORT)*8-1))) != 0); 845 if (LOWORD(lParam) == WM_LBUTTONUP && bAltPressed) 846 #else 471 847 if (LOWORD(lParam) == WM_RBUTTONUP) 848 #endif 472 849 { 473 if (!menu.LoadMenu(m_tnd.uID)) return(0); 850 if (!menu.LoadMenu(m_tnd.uID)) 851 return 0; 474 852 475 853 pSubMenu = menu.GetSubMenu(0); 476 if (!pSubMenu) return(0); 477 854 if (!pSubMenu) 855 return 0; 856 857 #ifndef _WIN32_WCE 478 858 // Make chosen menu item the default (bold font) 479 859 ::SetMenuDefaultItem(pSubMenu->m_hMenu, m_DefaultMenuItemID, m_DefaultMenuItemByPos); 480 481 // Delete unwanted items 482 UINT uIndex, uSize = m_ItemsToDelete.GetSize(); 483 for (uIndex = 0; uIndex < uSize; uIndex++) 484 pSubMenu->DeleteMenu(m_ItemsToDelete[uIndex], MF_BYCOMMAND); 485 486 // Check items 487 uSize = m_ItemsToCheck.GetSize(); 488 for (uIndex = 0; uIndex < uSize; uIndex++) 489 pSubMenu->CheckMenuItem(m_ItemsToCheck[uIndex], MF_BYCOMMAND | MF_CHECKED); 490 491 // Disable items 492 uSize = m_ItemsToDisable.GetSize(); 493 for (uIndex = 0; uIndex < uSize; uIndex++) 494 pSubMenu->EnableMenuItem(m_ItemsToDisable[uIndex], MF_DISABLED | MF_GRAYED | MF_BYCOMMAND); 860 #endif 861 862 CustomizeMenu(pSubMenu); 495 863 496 864 // Display and track the popup menu 497 865 CPoint pos; 866 #ifdef _WIN32_WCE 867 pos = CPoint(GetMessagePos()); 868 #else 498 869 GetCursorPos(&pos); 499 500 pTarget->SetForegroundWindow(); 870 #endif 871 872 pTargetWnd->SetForegroundWindow(); 873 874 #ifndef _WIN32_WCE 501 875 ::TrackPopupMenu(pSubMenu->m_hMenu, 0, pos.x, pos.y, 0, 502 pTarget->GetSafeHwnd(), NULL); 876 pTargetWnd->GetSafeHwnd(), NULL); 877 #else 878 pSubMenu->TrackPopupMenu(TPM_LEFTALIGN, pos.x, pos.y, pTargetWnd, NULL); 879 #endif 503 880 504 881 // BUGFIX: See "PRB: Menus for Notification Icons Don't Work Correctly" 505 pTarget ->PostMessage(WM_NULL, 0, 0);882 pTargetWnd->PostMessage(WM_NULL, 0, 0); 506 883 507 884 menu.DestroyMenu(); 508 885 } 886 #if defined(_WIN32_WCE) //&& _WIN32_WCE < 211 887 if (LOWORD(lParam) == WM_LBUTTONDBLCLK && bAltPressed) 888 #else 509 889 else if (LOWORD(lParam) == WM_LBUTTONDBLCLK) 890 #endif 510 891 { 511 892 // double click received, the default action is to execute default menu item 512 pTarget ->SetForegroundWindow();893 pTargetWnd->SetForegroundWindow(); 513 894 514 895 UINT uItem; 515 896 if (m_DefaultMenuItemByPos) 516 897 { 517 if (!menu.LoadMenu(m_tnd.uID)) return(0); 898 if (!menu.LoadMenu(m_tnd.uID)) 899 return 0; 900 518 901 pSubMenu = menu.GetSubMenu(0); 519 if (!pSubMenu) return(0); 520 902 if (!pSubMenu) 903 return 0; 904 521 905 uItem = pSubMenu->GetMenuItemID(m_DefaultMenuItemID); 906 907 menu.DestroyMenu(); 522 908 } 523 909 else 524 910 uItem = m_DefaultMenuItemID; 525 911 526 pTarget->SendMessage(WM_COMMAND, uItem, 0); 527 528 menu.DestroyMenu(); 529 } 530 531 return(1); 912 pTargetWnd->PostMessage(WM_COMMAND, uItem, 0); 913 } 914 915 return 1; 532 916 } 533 917 … … 536 920 if (message == m_tnd.uCallbackMessage) 537 921 return OnTrayNotification(wParam, lParam); 922 923 return CWnd::WindowProc(message, wParam, lParam); 924 } 925 926 void CSystemTray::InstallIconPending() 927 { 928 // Is the icon display pending, and it's not been set as "hidden"? 929 if (!m_bShowIconPending || m_bHidden) 930 return; 931 932 // Reset the flags to what was used at creation 933 m_tnd.uFlags = m_uCreationFlags; 934 935 // Try and recreate the icon 936 m_bHidden = !Shell_NotifyIcon(NIM_ADD, &m_tnd); 937 938 // If it's STILL hidden, then have another go next time... 939 m_bShowIconPending = m_bHidden; 940 941 ASSERT(m_bHidden == FALSE); 942 } 943 944 ///////////////////////////////////////////////////////////////////////////// 945 // For minimising/maximising from system tray 946 947 BOOL CALLBACK FindTrayWnd(HWND hwnd, LPARAM lParam) 948 { 949 TCHAR szClassName[256]; 950 GetClassName(hwnd, szClassName, 255); 951 952 // Did we find the Main System Tray? If so, then get its size and keep going 953 if (_tcscmp(szClassName, _T("TrayNotifyWnd")) == 0) 954 { 955 CRect *pRect = (CRect*) lParam; 956 ::GetWindowRect(hwnd, pRect); 957 return TRUE; 958 } 959 960 // Did we find the System Clock? If so, then adjust the size of the rectangle 961 // we have and quit (clock will be found after the system tray) 962 if (_tcscmp(szClassName, _T("TrayClockWClass")) == 0) 963 { 964 CRect *pRect = (CRect*) lParam; 965 CRect rectClock; 966 ::GetWindowRect(hwnd, rectClock); 967 // if clock is above system tray adjust accordingly 968 if (rectClock.bottom < pRect->bottom-5) // 10 = random fudge factor. 969 pRect->top = rectClock.bottom; 970 else 971 pRect->right = rectClock.left; 972 return FALSE; 973 } 974 975 return TRUE; 976 } 977 978 #ifndef _WIN32_WCE 979 // enhanced version by Matthew Ellis <m.t.ellis@bigfoot.com> 980 void CSystemTray::GetTrayWndRect(LPRECT lprect) 981 { 982 #define DEFAULT_RECT_WIDTH 150 983 #define DEFAULT_RECT_HEIGHT 30 984 985 HWND hShellTrayWnd = ::FindWindow(_T("Shell_TrayWnd"), NULL); 986 if (hShellTrayWnd) 987 { 988 ::GetWindowRect(hShellTrayWnd, lprect); 989 EnumChildWindows(hShellTrayWnd, FindTrayWnd, (LPARAM)lprect); 990 return; 991 } 992 // OK, we failed to get the rect from the quick hack. Either explorer isn't 993 // running or it's a new version of the shell with the window class names 994 // changed (how dare Microsoft change these undocumented class names!) So, we 995 // try to find out what side of the screen the taskbar is connected to. We 996 // know that the system tray is either on the right or the bottom of the 997 // taskbar, so we can make a good guess at where to minimize to 998 APPBARDATA appBarData; 999 appBarData.cbSize=sizeof(appBarData); 1000 if (SHAppBarMessage(ABM_GETTASKBARPOS,&appBarData)) 1001 { 1002 // We know the edge the taskbar is connected to, so guess the rect of the 1003 // system tray. Use various fudge factor to make it look good 1004 switch(appBarData.uEdge) 1005 { 1006 case ABE_LEFT: 1007 case ABE_RIGHT: 1008 // We want to minimize to the bottom of the taskbar 1009 lprect->top = appBarData.rc.bottom-100; 1010 lprect->bottom = appBarData.rc.bottom-16; 1011 lprect->left = appBarData.rc.left; 1012 lprect->right = appBarData.rc.right; 1013 break; 1014 1015 case ABE_TOP: 1016 case ABE_BOTTOM: 1017 // We want to minimize to the right of the taskbar 1018 lprect->top = appBarData.rc.top; 1019 lprect->bottom = appBarData.rc.bottom; 1020 lprect->left = appBarData.rc.right-100; 1021 lprect->right = appBarData.rc.right-16; 1022 break; 1023 } 1024 return; 1025 } 538 1026 539 return CWnd::WindowProc(message, wParam, lParam); 540 } 1027 // Blimey, we really aren't in luck. It's possible that a third party shell 1028 // is running instead of explorer. This shell might provide support for the 1029 // system tray, by providing a Shell_TrayWnd window (which receives the 1030 // messages for the icons) So, look for a Shell_TrayWnd window and work out 1031 // the rect from that. Remember that explorer's taskbar is the Shell_TrayWnd, 1032 // and stretches either the width or the height of the screen. We can't rely 1033 // on the 3rd party shell's Shell_TrayWnd doing the same, in fact, we can't 1034 // rely on it being any size. The best we can do is just blindly use the 1035 // window rect, perhaps limiting the width and height to, say 150 square. 1036 // Note that if the 3rd party shell supports the same configuraion as 1037 // explorer (the icons hosted in NotifyTrayWnd, which is a child window of 1038 // Shell_TrayWnd), we would already have caught it above 1039 if (hShellTrayWnd) 1040 { 1041 ::GetWindowRect(hShellTrayWnd, lprect); 1042 if (lprect->right - lprect->left > DEFAULT_RECT_WIDTH) 1043 lprect->left = lprect->right - DEFAULT_RECT_WIDTH; 1044 if (lprect->bottom - lprect->top > DEFAULT_RECT_HEIGHT) 1045 lprect->top = lprect->bottom - DEFAULT_RECT_HEIGHT; 1046 1047 return; 1048 } 1049 1050 // OK. Haven't found a thing. Provide a default rect based on the current work 1051 // area 1052 SystemParametersInfo(SPI_GETWORKAREA,0, lprect, 0); 1053 lprect->left = lprect->right - DEFAULT_RECT_WIDTH; 1054 lprect->top = lprect->bottom - DEFAULT_RECT_HEIGHT; 1055 } 1056 1057 // Check to see if the animation has been disabled (Matthew Ellis <m.t.ellis@bigfoot.com>) 1058 BOOL CSystemTray::GetDoWndAnimation() 1059 { 1060 ANIMATIONINFO ai; 1061 1062 ai.cbSize=sizeof(ai); 1063 SystemParametersInfo(SPI_GETANIMATION,sizeof(ai),&ai,0); 1064 1065 return ai.iMinAnimate?TRUE:FALSE; 1066 } 1067 #endif 1068 1069 BOOL CSystemTray::RemoveTaskbarIcon(CWnd* pWnd) 1070 { 1071 LPCTSTR pstrOwnerClass = AfxRegisterWndClass(0); 1072 1073 // Create static invisible window 1074 if (!::IsWindow(m_wndInvisible.m_hWnd)) 1075 { 1076 if (!m_wndInvisible.CreateEx(0, pstrOwnerClass, _T(""), WS_POPUP, 1077 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 1078 NULL, 0)) 1079 return FALSE; 1080 } 1081 1082 pWnd->SetParent(&m_wndInvisible); 1083 1084 return TRUE; 1085 } 1086 1087 void CSystemTray::MinimiseToTray(CWnd* pWnd, BOOL bForceAnimation /*= FALSE*/) 1088 { 1089 #ifndef _WIN32_WCE 1090 if (bForceAnimation || GetDoWndAnimation()) 1091 { 1092 CRect rectFrom, rectTo; 1093 1094 pWnd->GetWindowRect(rectFrom); 1095 GetTrayWndRect(rectTo); 1096 1097 ::DrawAnimatedRects(pWnd->m_hWnd, IDANI_CAPTION, rectFrom, rectTo); 1098 } 1099 1100 RemoveTaskbarIcon(pWnd); 1101 pWnd->ModifyStyle(WS_VISIBLE, 0); 1102 #endif 1103 } 1104 1105 void CSystemTray::MaximiseFromTray(CWnd* pWnd, BOOL bForceAnimation /*= TRUE*/) 1106 { 1107 #ifndef _WIN32_WCE 1108 if (bForceAnimation || GetDoWndAnimation()) 1109 { 1110 CRect rectTo; 1111 pWnd->GetWindowRect(rectTo); 1112 1113 CRect rectFrom; 1114 GetTrayWndRect(rectFrom); 1115 1116 pWnd->SetParent(NULL); 1117 ::DrawAnimatedRects(pWnd->m_hWnd, IDANI_CAPTION, rectFrom, rectTo); 1118 } 1119 else 1120 pWnd->SetParent(NULL); 1121 1122 pWnd->ModifyStyle(0, WS_VISIBLE); 1123 pWnd->RedrawWindow(NULL, NULL, RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_FRAME | 1124 RDW_INVALIDATE | RDW_ERASE); 1125 1126 // Move focus away and back again to ensure taskbar icon is recreated 1127 if (::IsWindow(m_wndInvisible.m_hWnd)) 1128 m_wndInvisible.SetActiveWindow(); 1129 pWnd->SetActiveWindow(); 1130 pWnd->SetForegroundWindow(); 1131 #endif 1132 }
Note: See TracChangeset
for help on using the changeset viewer.
