// // utbtray.cpp // #include "private.h" #include "globals.h" #include "utbtray.h" #include "inatlib.h" #include "xstring.h" #include "inatlib.h" #include "tipbar.h" #include "shlapip.h" #include "nuiinat.h" #include "resource.h" #include "cresstr.h" #include "cregkey.h" #include "nuiinat.h" #include "dlgs.h" HICON WINAPI TF_GetLangIcon(WORD langid , WCHAR *psz, UINT cchMax); const char CTrayIconWnd::_szWndClass[] = "CTrayIconWndClass"; extern UINT g_wmTaskbarCreated; extern CTipbarWnd *g_pTipbarWnd; /* e0b724e9-6f76-45f7-b4c1-b1c0fabce23e */ const GUID GUID_LBI_TRAYMAIN = { 0xe0b724e9, 0x6f76, 0x45f7, {0xb4, 0xc1, 0xb1, 0xc0, 0xfa, 0xbc, 0xe2, 0x3e} }; ////////////////////////////////////////////////////////////////////////////// // // CTrayIconItem // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CTrayIconItem::CTrayIconItem(CTrayIconWnd *ptiwnd) { _fIconPrev = FALSE; _ptiwnd = ptiwnd; } //+--------------------------------------------------------------------------- // // dtor // //---------------------------------------------------------------------------- CTrayIconItem::~CTrayIconItem() { RemoveIcon(); } //+--------------------------------------------------------------------------- // // Init // //---------------------------------------------------------------------------- BOOL CTrayIconItem::_Init(HWND hwnd, UINT uCallbackMessage, UINT uID, REFGUID rguid) { _hwnd = hwnd; _uCallbackMessage = uCallbackMessage; _uID = uID; _guidBtnItem = rguid; return TRUE; } //+--------------------------------------------------------------------------- // // SetIcon // //---------------------------------------------------------------------------- BOOL CTrayIconItem::SetIcon(HICON hIcon, const WCHAR *pszTooltip) { DWORD dwMessage; if (!hIcon) return FALSE; if (!_fIconPrev) dwMessage = NIM_ADD; else dwMessage = NIM_MODIFY; if (IsOnNT()) { NOTIFYICONDATAW tndw; tndw.cbSize = sizeof(NOTIFYICONDATAW); tndw.hWnd = _hwnd; tndw.uCallbackMessage = _uCallbackMessage; tndw.uID = _uID; tndw.uFlags = NIF_MESSAGE | NIF_ICON; tndw.hIcon = hIcon; if (pszTooltip) { tndw.uFlags |= NIF_TIP; StringCchCopyW(tndw.szTip, ARRAYSIZE(tndw.szTip), pszTooltip); } Shell_NotifyIconW(dwMessage, &tndw); } else { NOTIFYICONDATA tnd; tnd.cbSize = sizeof(NOTIFYICONDATA); tnd.hWnd = _hwnd; tnd.uCallbackMessage = _uCallbackMessage; tnd.uID = _uID; tnd.uFlags = NIF_MESSAGE | NIF_ICON; tnd.hIcon = hIcon; if (pszTooltip) { tnd.uFlags |= NIF_TIP; StringCchCopyA(tnd.szTip, ARRAYSIZE(tnd.szTip), WtoA(pszTooltip)); } Shell_NotifyIcon(dwMessage, &tnd); } _fIconPrev = TRUE; _fShownInTray = TRUE; return TRUE; } //+--------------------------------------------------------------------------- // // RemoveIcon // //---------------------------------------------------------------------------- BOOL CTrayIconItem::RemoveIcon() { NOTIFYICONDATA tnd; if (_fIconPrev) // this check is esp useful because we delay load shell32.dll { tnd.cbSize = sizeof(NOTIFYICONDATA); tnd.hWnd = _hwnd; tnd.uCallbackMessage = _uCallbackMessage; tnd.uID = _uID; tnd.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; tnd.hIcon = NULL; tnd.szTip[0] = '\0'; Shell_NotifyIcon(NIM_DELETE, &tnd); } _fIconPrev = FALSE; _fShownInTray = FALSE; return TRUE; } //+--------------------------------------------------------------------------- // // UpdateMenuRectPoint // //---------------------------------------------------------------------------- BOOL CTrayIconItem::UpdateMenuRectPoint() { HWND hwndNotify = _ptiwnd->GetNotifyWnd(); GetClientRect(hwndNotify, &_rcClick); ClientToScreen(hwndNotify, (LPPOINT)&_rcClick.left); ClientToScreen(hwndNotify, (LPPOINT)&_rcClick.right); GetCursorPos(&_ptClick); // *ppt = *(LPPOINT)prc; // MapWindowPoints(hwndNotify, NULL, ppt, 2); return TRUE; } ////////////////////////////////////////////////////////////////////////////// // // CButtonIconItem // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CButtonIconItem::CButtonIconItem(CTrayIconWnd *ptiwnd, BOOL fMenuButtonItem) : CTrayIconItem(ptiwnd) { _fMenuButtonItem = fMenuButtonItem; } //+--------------------------------------------------------------------------- // // dtor // //---------------------------------------------------------------------------- CButtonIconItem::~CButtonIconItem() { } //+--------------------------------------------------------------------------- // // OnMsg // //---------------------------------------------------------------------------- BOOL CButtonIconItem::OnMsg(WPARAM wParam, LPARAM lParam) { CTipbarThread *ptt; if ((lParam == WM_LBUTTONDOWN) || (lParam == WM_RBUTTONDOWN) || (lParam == WM_LBUTTONDBLCLK) || (lParam == WM_RBUTTONDBLCLK)) { if (_ptiwnd->_fInTrayMenu) return FALSE; g_pTipbarWnd->CancelMenu(); _ptiwnd->_uCurCallbackMessage = _uCallbackMessage; _ptiwnd->_uCurMouseMessage = (UINT)lParam; ::KillTimer(_ptiwnd->GetWnd(), TRAYICONWND_TIMER_ONDELAYMSG); ::SetTimer(_ptiwnd->GetWnd(), TRAYICONWND_TIMER_ONDELAYMSG, g_uTimerElapseTRAYWNDONDELAYMSG, NULL); ptt = g_pTipbarWnd->GetFocusThread(); g_pTipbarWnd->RestoreLastFocus(&_dwThreadFocus, TRUE); if (ptt && (ptt->_dwThreadId == _dwThreadFocus)) g_pTipbarWnd->SetWaitNotifyThread(_dwThreadFocus); else g_pTipbarWnd->SetWaitNotifyThread(0); UpdateMenuRectPoint(); } return TRUE; } //+--------------------------------------------------------------------------- // // OnDelayMsg // //---------------------------------------------------------------------------- BOOL CButtonIconItem::OnDelayMsg(UINT uMsg) { CTipbarThread *ptt; CTipbarButtonItem *pLangBtn; BOOL bRet = FALSE; _ptiwnd->_fInTrayMenu = TRUE; Assert((uMsg == WM_LBUTTONDOWN) || (uMsg == WM_RBUTTONDOWN) || (uMsg == WM_LBUTTONDBLCLK) || (uMsg == WM_RBUTTONDBLCLK)); g_pTipbarWnd->SetWaitNotifyThread(0); if (!_dwThreadFocus) { // // we failed to set foreground at OnMsg. // so we try again here. // g_pTipbarWnd->RestoreLastFocus(&_dwThreadFocus, TRUE); // if (!_dwThreadFocus) // { // // ok now we give up to restore focus. // // MessageBeep(0); // goto Exit; // } } _dwThreadFocus = 0; ptt = g_pTipbarWnd->GetFocusThread(); if (!ptt) goto Exit; if (g_pTipbarWnd->IsInItemChangeOrDirty(ptt)) { ::KillTimer(_ptiwnd->GetWnd(), TRAYICONWND_TIMER_ONDELAYMSG); ::SetTimer(_ptiwnd->GetWnd(), TRAYICONWND_TIMER_ONDELAYMSG, g_uTimerElapseTRAYWNDONDELAYMSG, NULL); goto Exit; } pLangBtn = (CTipbarButtonItem *)(ptt->GetItem(_guidBtnItem)); if (!pLangBtn) { if (IsEqualGUID(_guidBtnItem, GUID_LBI_CTRL)) { pLangBtn = (CTipbarButtonItem *)(ptt->GetItem(GUID_LBI_INATITEM)); if (!pLangBtn) goto Exit; } else { // // In this case, it is MSUTB's CLBarInatItem. // bRet = TRUE; goto Exit; } } if (uMsg == WM_LBUTTONDOWN) { if (_fMenuButtonItem) { g_pTipbarWnd->CancelMenu(); pLangBtn->DoModalMenu(&_ptClick, &_rcClick); } else { pLangBtn->OnLeftClick(); } } else if (uMsg == WM_RBUTTONDOWN) { if (IsEqualGUID(_guidBtnItem, GUID_LBI_CTRL) || IsEqualGUID(_guidBtnItem, GUID_TFCAT_TIP_KEYBOARD)) { g_pTipbarWnd->ShowContextMenu(_ptClick, &_rcClick, TRUE); } else { pLangBtn->OnRightClick(); } } else if (uMsg == WM_LBUTTONDBLCLK) { if (IsEqualGUID(_guidBtnItem, GUID_LBI_CTRL)) { g_pTipbarWnd->GetLangBarMgr()->ShowFloating(TF_SFT_SHOWNORMAL); } } bRet = TRUE; Exit: _ptiwnd->_fInTrayMenu = FALSE; return bRet; } ////////////////////////////////////////////////////////////////////////////// // // CMainIconItem // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // OnDelayMsg // //---------------------------------------------------------------------------- BOOL CMainIconItem::OnDelayMsg(UINT uMsg) { BOOL bRet = CButtonIconItem::OnDelayMsg(uMsg); if (!bRet) return bRet; if (uMsg == WM_LBUTTONDBLCLK) { if (g_pTipbarWnd->_fIsItemShownInFloatingToolbar) g_pTipbarWnd->GetLangBarMgr()->ShowFloating(TF_SFT_SHOWNORMAL); } else if ((uMsg == WM_LBUTTONDOWN) || (uMsg == WM_RBUTTONDOWN)) { g_pTipbarWnd->ShowContextMenu(_ptClick, &_rcClick, (uMsg == WM_RBUTTONDOWN)); } return bRet; } ////////////////////////////////////////////////////////////////////////////// // // CTrayIconWnd // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // ctor // //---------------------------------------------------------------------------- CTrayIconWnd::CTrayIconWnd() { _uNextMsg = WM_TIW_START; _uNextID = TIW_INDICATOR_ID_START; } //+--------------------------------------------------------------------------- // // dtor // //---------------------------------------------------------------------------- CTrayIconWnd::~CTrayIconWnd() { int nCnt = _rgIconItems.Count(); int i; for ( i = 0; i < nCnt; i++) { CTrayIconItem *pItem = _rgIconItems.Get(i); delete pItem; } } //+--------------------------------------------------------------------------- // // CreateWnd // //---------------------------------------------------------------------------- HWND CTrayIconWnd::CreateWnd() { _hWnd = CreateWindowEx(0, _szWndClass, TEXT(""), WS_DISABLED, 0, 0, 0, 0, NULL, 0, g_hInst, this); FindTrayEtc(); CTrayIconItem **ppItem; _ptiiMain = new CMainIconItem(this); if (_ptiiMain) { _ptiiMain->Init(_hWnd); ppItem = _rgIconItems.Append(1); if (ppItem) *ppItem = _ptiiMain; } return _hWnd; } //+--------------------------------------------------------------------------- // // RegisterClass // //---------------------------------------------------------------------------- BOOL CTrayIconWnd::RegisterClass() { WNDCLASSEX wc; memset(&wc, 0, sizeof(wc)); wc.cbSize = sizeof(wc); wc.style = CS_HREDRAW | CS_VREDRAW ; wc.hInstance = g_hInst; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpfnWndProc = _WndProc; wc.lpszClassName = _szWndClass; ::RegisterClassEx(&wc); return TRUE; } //--------------------------------------------------------------------------- // // BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam) // // Look at the class names using GetClassName to see if you can find the // Tray notification Window. // //--------------------------------------------------------------------------- static TCHAR szNotifyWindow[] = TEXT("TrayNotifyWnd"); BOOL CALLBACK CTrayIconWnd::EnumChildWndProc(HWND hwnd, LPARAM lParam) { char szString[50]; CTrayIconWnd *_this = (CTrayIconWnd *)lParam; GetClassName(hwnd, (LPSTR) szString, sizeof(szString)); if (0 == lstrcmp(szString, szNotifyWindow)) { _this->_hwndNotify = hwnd; return FALSE; } return TRUE; } BOOL CTrayIconWnd::FindTrayEtc() { _hwndTray = FindWindow(TEXT(WNDCLASS_TRAYNOTIFY), NULL); if (!_hwndTray) { return FALSE; } EnumChildWindows(_hwndTray, (WNDENUMPROC)EnumChildWndProc, (LPARAM)this); if (!_hwndNotify) { return FALSE; } _dwThreadIdTray = GetWindowThreadProcessId(_hwndTray, NULL); _hwndProgman = FindWindow("Progman", NULL); _dwThreadIdProgman = GetWindowThreadProcessId(_hwndProgman, NULL); return TRUE; } //+--------------------------------------------------------------------------- // // _WndProc // //---------------------------------------------------------------------------- void CTrayIconWnd::CallOnDelayMsg() { int nCnt = _rgIconItems.Count(); int i; BOOL bRet = FALSE; CTrayIconItem *pItem = NULL; for ( i = 0; i < nCnt; i++) { CTrayIconItem *pItemTemp = _rgIconItems.Get(i); if (_uCurCallbackMessage == pItemTemp->GetMsg()) { pItem = pItemTemp; break; } } if (!pItem) return; pItem->OnDelayMsg(_uCurMouseMessage); } //+--------------------------------------------------------------------------- // // _WndProc // //---------------------------------------------------------------------------- LRESULT CALLBACK CTrayIconWnd::_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CTrayIconWnd *_this; switch (uMsg) { case WM_CREATE: SetThis(hWnd, lParam); break; case WM_DESTROY: SetThis(hWnd, 0); break; case WM_TIMER: { if (wParam == TRAYICONWND_TIMER_ONDELAYMSG) { ::KillTimer(hWnd, TRAYICONWND_TIMER_ONDELAYMSG); _this = GetThis(hWnd); if (_this) _this->CallOnDelayMsg(); } } break; default: if (uMsg >= WM_USER) { _this = GetThis(hWnd); if (!_this || !_this->OnIconMessage(uMsg, wParam, lParam)) return DefWindowProc(hWnd, uMsg, wParam, lParam); } else { return DefWindowProc(hWnd, uMsg, wParam, lParam); } } return 0; } //+--------------------------------------------------------------------------- // // SetMainIcon // //---------------------------------------------------------------------------- BOOL CTrayIconWnd::SetMainIcon(HKL hkl) { if (hkl) { HICON hIcon; WCHAR wsz[64]; if (hkl == _ptiiMain->_hkl) return TRUE; hIcon = TF_GetLangIcon((LANGID)HandleToUlong(hkl), wsz, ARRAYSIZE(wsz)); if (hIcon) { _ptiiMain->SetIcon(hIcon, wsz); DestroyIcon(hIcon); } else _ptiiMain->SetIcon(LoadIcon(g_hInst, MAKEINTRESOURCE(ID_ICON_CONTROLBTN)), CRStr(IDS_CONTROLBTN)); _ptiiMain->_hkl = hkl; } else { _ptiiMain->RemoveIcon(); _ptiiMain->_hkl = NULL; } return TRUE; } //+--------------------------------------------------------------------------- // // OnIconMessage // //---------------------------------------------------------------------------- BOOL CTrayIconWnd::OnIconMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) { int nCnt = _rgIconItems.Count(); int i; BOOL bRet = FALSE; if (g_pTipbarWnd) g_pTipbarWnd->AttachFocusThread(); for ( i = 0; i < nCnt; i++) { CTrayIconItem *pItem = _rgIconItems.Get(i); if (uMsg == pItem->GetMsg()) { pItem->OnMsg(wParam, lParam); bRet = TRUE; break; } } return bRet; } //+--------------------------------------------------------------------------- // // SetIcon // //---------------------------------------------------------------------------- BOOL CTrayIconWnd::SetIcon(REFGUID rguid, BOOL fMenu, HICON hIcon, const WCHAR *pszToolTip) { BOOL bRet; CTrayIconItem *pItem; pItem = FindIconItem(rguid); // // we don't have to create new Itom to be removed. // if (!pItem && hIcon) { CTrayIconItem **ppItem; pItem = new CButtonIconItem(this, fMenu); if (!pItem) return FALSE; pItem->_Init(GetWnd(), _uNextMsg, _uNextID, rguid); _uNextMsg += 2; _uNextID += 1; // // check if these numbers dont go over. // Assert(_uNextMsg >= WM_USER); Assert(_uNextMsg < WM_APP); Assert(_uNextID < 0x8000000); ppItem = _rgIconItems.Append(1); if (ppItem) *ppItem = pItem; } if (!pItem) return FALSE; if (hIcon) bRet = pItem->SetIcon(hIcon, pszToolTip); else bRet = pItem->RemoveIcon(); return bRet; } //+--------------------------------------------------------------------------- // // RemoveUnusedIcons // //---------------------------------------------------------------------------- void CTrayIconWnd::RemoveUnusedIcons(CPtrArray *prgItem) { int i,j; for (i = 0;i < _rgIconItems.Count(); i++) { CTrayIconItem *pItem = _rgIconItems.Get(i); BOOL fFound; if (IsEqualGUID(GUID_LBI_TRAYMAIN, *pItem->GetGuid())) continue; fFound = FALSE; for (j = 0;j < prgItem->Count(); j++) { CTipbarItem *pTipbarItem = prgItem->Get(j); // // in case, this item is in tray icon... // The item may be "show satus" in other thread. // // if (!pTipbarItem->IsShown()) // continue; if (IsEqualGUID(*pTipbarItem->GetGUID(), *pItem->GetGuid())) { fFound = TRUE; break; } } if (!fFound) { pItem->RemoveIcon(); } } return; }