Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

765 lines
19 KiB

//
// 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<CTipbarItem> *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;
}