mirror of https://github.com/lianthony/NT4.0
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.
1135 lines
29 KiB
1135 lines
29 KiB
#include "cabinet.h"
|
|
#include "trayclok.h"
|
|
#include "traynot.h"
|
|
#include "rcids.h"
|
|
|
|
typedef struct _TNPRIVDATA
|
|
{
|
|
HWND hwndNotify;
|
|
HWND hwndClock;
|
|
HWND hwndToolTips;
|
|
RECT rNotifies;
|
|
HDPA hdpaIcons;
|
|
HIMAGELIST himlIcons;
|
|
COLORREF clBk;
|
|
int nCols;
|
|
} TNPRIVDATA, *PTNPRIVDATA;
|
|
|
|
typedef struct _TNPRIVICON
|
|
{
|
|
UINT uIMLIndex;
|
|
NOTIFYICONDATA tnd;
|
|
} TNPRIVICON, *PTNPRIVICON;
|
|
|
|
|
|
void Tray_SizeWindows();
|
|
|
|
|
|
const TCHAR c_szTrayNotify[] = TEXT("TrayNotifyWnd");
|
|
|
|
/*
|
|
** _TNResetToolTipsRects
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
void _TNResetToolTipsRects(PTNPRIVDATA pTNPrivData)
|
|
{
|
|
TOOLINFO ti;
|
|
PTNPRIVICON pTNPrivIcon;
|
|
int i, nIcons;
|
|
UINT xIcon, yIcon;
|
|
int x, y;
|
|
|
|
// change all the rects for the tool tips mgr. this is
|
|
// cheap, and we don't do it often, so go ahead
|
|
// and do them all.
|
|
if(!pTNPrivData->hwndToolTips)
|
|
{
|
|
return;
|
|
}
|
|
|
|
xIcon = GetSystemMetrics(SM_CXSMICON);
|
|
yIcon = GetSystemMetrics(SM_CYSMICON);
|
|
|
|
x = pTNPrivData->rNotifies.left;
|
|
y = pTNPrivData->rNotifies.top;
|
|
|
|
ti.cbSize = SIZEOF(ti);
|
|
ti.uFlags = 0;
|
|
ti.hwnd = pTNPrivData->hwndNotify;
|
|
ti.lpszText = LPSTR_TEXTCALLBACK;
|
|
|
|
nIcons = DPA_GetPtrCount(pTNPrivData->hdpaIcons);
|
|
for (i=0; i<nIcons; )
|
|
{
|
|
pTNPrivIcon = DPA_FastGetPtr(pTNPrivData->hdpaIcons, i);
|
|
|
|
ti.uId = (UINT)pTNPrivIcon;
|
|
ti.rect.left = x;
|
|
ti.rect.top = y;
|
|
ti.rect.right = x + xIcon;
|
|
ti.rect.bottom = y + yIcon;
|
|
SendMessage(pTNPrivData->hwndToolTips, TTM_NEWTOOLRECT,
|
|
0, (LPARAM)((LPTOOLINFO)&ti));
|
|
|
|
x += xIcon + g_cxBorder;
|
|
|
|
++i;
|
|
if (i%pTNPrivData->nCols == 0)
|
|
{
|
|
y += yIcon + g_cyBorder;
|
|
x = pTNPrivData->rNotifies.left;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
** _TNRemoveImage
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
void _TNRemoveImage(PTNPRIVDATA pTNPrivData, UINT uIMLIndex)
|
|
{
|
|
int nIcon;
|
|
PTNPRIVICON pTNPrivIcon;
|
|
|
|
if (uIMLIndex != (UINT)-1)
|
|
ImageList_Remove(pTNPrivData->himlIcons, uIMLIndex);
|
|
|
|
// Adjust the ImageList indices for all other icons
|
|
for (nIcon=DPA_GetPtrCount(pTNPrivData->hdpaIcons)-1; nIcon>=0; --nIcon)
|
|
{
|
|
pTNPrivIcon = DPA_GetPtr(pTNPrivData->hdpaIcons, nIcon);
|
|
if (pTNPrivIcon->uIMLIndex > uIMLIndex)
|
|
{
|
|
--pTNPrivIcon->uIMLIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
** _TNFindNotify
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
int _TNFindNotify(PTNPRIVDATA pTNPrivData, PNOTIFYICONDATA pTND)
|
|
{
|
|
int i;
|
|
PTNPRIVICON pTNPrivIcon;
|
|
|
|
for (i=DPA_GetPtrCount(pTNPrivData->hdpaIcons)-1; i>=0; --i)
|
|
{
|
|
pTNPrivIcon = DPA_GetPtr(pTNPrivData->hdpaIcons, i);
|
|
if (pTNPrivIcon->tnd.hWnd==pTND->hWnd && pTNPrivIcon->tnd.uID==pTND->uID)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(i);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Returns TRUE if either the images are OK as they are or they needed
|
|
// resizing and the resize process worked. FALSE otherwise.
|
|
BOOL _TNCheckAndResizeImages(PTNPRIVDATA pTNPrivData)
|
|
{
|
|
HIMAGELIST himlOld, himlNew;
|
|
int cxSmIconNew, cySmIconNew, cxSmIconOld, cySmIconOld;
|
|
int i, cItems;
|
|
COLORREF clBkNew;
|
|
HICON hicon;
|
|
BOOL fOK = TRUE;
|
|
|
|
if (!pTNPrivData)
|
|
return 0;
|
|
|
|
himlOld = pTNPrivData->himlIcons;
|
|
|
|
// Do dimensions match current icons?
|
|
cxSmIconNew = GetSystemMetrics(SM_CXSMICON);
|
|
cySmIconNew = GetSystemMetrics(SM_CYSMICON);
|
|
ImageList_GetIconSize(himlOld, &cxSmIconOld, &cySmIconOld);
|
|
if (cxSmIconNew != cxSmIconOld || cxSmIconNew != cxSmIconOld)
|
|
{
|
|
// Nope, we're gonna need a new imagelist.
|
|
himlNew = ImageList_Create(cxSmIconNew, cySmIconNew, TRUE, 0, 1);
|
|
if (himlNew)
|
|
{
|
|
clBkNew = GetSysColor(COLOR_3DFACE);
|
|
ImageList_SetBkColor(himlNew, clBkNew);
|
|
|
|
// Copy the images over to the new image list.
|
|
cItems = ImageList_GetImageCount(himlOld);
|
|
for (i = 0; i < cItems; i++)
|
|
{
|
|
// REVIEW Lame - there's no way to copy images to an empty
|
|
// imagelist, resizing it on the way.
|
|
hicon = ImageList_GetIcon(himlOld, i, ILD_NORMAL);
|
|
if (hicon)
|
|
{
|
|
if (ImageList_AddIcon(himlNew, hicon) == -1)
|
|
{
|
|
// Couldn't copy image so bail.
|
|
fOK = FALSE;
|
|
}
|
|
DestroyIcon(hicon);
|
|
}
|
|
else
|
|
{
|
|
fOK = FALSE;
|
|
}
|
|
|
|
// FU - bail.
|
|
if (!fOK)
|
|
break;
|
|
}
|
|
|
|
// Did everything copy over OK?
|
|
if (fOK)
|
|
{
|
|
// Yep, Set things up to use the new one.
|
|
pTNPrivData->himlIcons = himlNew;
|
|
// Destroy the old icon cache.
|
|
ImageList_Destroy(himlOld);
|
|
}
|
|
else
|
|
{
|
|
// Nope, stick with what we have.
|
|
ImageList_Destroy(himlNew);
|
|
}
|
|
}
|
|
}
|
|
|
|
return fOK;
|
|
}
|
|
|
|
|
|
/*
|
|
** _TNModifyNotify
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
BOOL _TNModifyNotify(PTNPRIVDATA pTNPrivData, PNOTIFYICONDATA pnid, int nIcon)
|
|
{
|
|
PTNPRIVICON pTNPrivIcon;
|
|
UINT uIMLIndex, uIMLNew;
|
|
|
|
pTNPrivIcon = DPA_GetPtr(pTNPrivData->hdpaIcons, nIcon);
|
|
if (!pTNPrivIcon)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
_TNCheckAndResizeImages(pTNPrivData);
|
|
|
|
// The icon is the only thing that can fail, so I will do it first
|
|
if (pnid->uFlags&NIF_ICON)
|
|
{
|
|
if (pnid->hIcon)
|
|
{
|
|
// Replace icon knows how to handle -1 for add
|
|
uIMLNew = ImageList_ReplaceIcon(pTNPrivData->himlIcons,
|
|
pTNPrivIcon->uIMLIndex, pnid->hIcon);
|
|
if ((int)uIMLNew < 0)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_TNRemoveImage(pTNPrivData, pTNPrivIcon->uIMLIndex);
|
|
uIMLNew = (UINT)-1;
|
|
}
|
|
pTNPrivIcon->uIMLIndex = uIMLNew;
|
|
}
|
|
|
|
if (pnid->uFlags&NIF_MESSAGE)
|
|
{
|
|
pTNPrivIcon->tnd.uCallbackMessage = pnid->uCallbackMessage;
|
|
}
|
|
if (pnid->uFlags&NIF_TIP)
|
|
{
|
|
lstrcpyn(pTNPrivIcon->tnd.szTip, pnid->szTip,
|
|
ARRAYSIZE(pTNPrivIcon->tnd.szTip));
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
** _TNDeleteNotify
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
BOOL _TNDeleteNotify(PTNPRIVDATA pTNPrivData, int nIcon)
|
|
{
|
|
PTNPRIVICON pTNPrivIcon;
|
|
UINT uIMLIndex;
|
|
|
|
pTNPrivIcon = DPA_GetPtr(pTNPrivData->hdpaIcons, nIcon);
|
|
if (!pTNPrivIcon)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
DPA_DeletePtr(pTNPrivData->hdpaIcons, nIcon);
|
|
|
|
if(pTNPrivData->hwndToolTips)
|
|
{
|
|
TOOLINFO ti;
|
|
ti.cbSize = SIZEOF(ti);
|
|
ti.hwnd = pTNPrivData->hwndNotify;
|
|
ti.uId = (UINT)pTNPrivIcon;
|
|
SendMessage(pTNPrivData->hwndToolTips, TTM_DELTOOL,
|
|
0, (LPARAM)(LPTOOLINFO)&ti);
|
|
}
|
|
|
|
uIMLIndex = pTNPrivIcon->uIMLIndex;
|
|
_TNRemoveImage(pTNPrivData, uIMLIndex);
|
|
|
|
LocalFree((HLOCAL)pTNPrivIcon);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
** _TNInsertNotify
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
BOOL _TNInsertNotify(PTNPRIVDATA pTNPrivData, PNOTIFYICONDATA pnid, int insert)
|
|
{
|
|
PTNPRIVICON pTNPrivIcon;
|
|
|
|
// First insert a totally "default" icon
|
|
pTNPrivIcon = LocalAlloc(LPTR, SIZEOF(TNPRIVICON));
|
|
if (!pTNPrivIcon)
|
|
{
|
|
goto Error1;
|
|
}
|
|
|
|
pTNPrivIcon->uIMLIndex = (UINT)-1;
|
|
pTNPrivIcon->tnd.hWnd = pnid->hWnd;
|
|
pTNPrivIcon->tnd.uID = pnid->uID;
|
|
|
|
insert = DPA_InsertPtr(pTNPrivData->hdpaIcons, insert, pTNPrivIcon);
|
|
if (insert == -1)
|
|
{
|
|
goto Error2;
|
|
}
|
|
|
|
if(pTNPrivData->hwndToolTips)
|
|
{
|
|
TOOLINFO ti;
|
|
|
|
// don't bother setting the rect because we'll do it soon
|
|
// anyway later;
|
|
ti.cbSize = SIZEOF(ti);
|
|
ti.uFlags = 0;
|
|
ti.hwnd = pTNPrivData->hwndNotify;
|
|
ti.uId = (UINT)pTNPrivIcon;
|
|
ti.lpszText = LPSTR_TEXTCALLBACK;
|
|
SendMessage(pTNPrivData->hwndToolTips, TTM_ADDTOOL,
|
|
0, (LPARAM)(LPTOOLINFO)&ti);
|
|
}
|
|
|
|
// Then modify this icon with the specified info
|
|
if (!_TNModifyNotify(pTNPrivData, pnid, insert))
|
|
{
|
|
_TNDeleteNotify(pTNPrivData, insert);
|
|
// Note that we do not go to the LocalFree
|
|
goto Error1;
|
|
}
|
|
|
|
return(TRUE);
|
|
|
|
Error2:
|
|
LocalFree((HLOCAL)pTNPrivIcon);
|
|
Error1:
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
** _TNCreate
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
LRESULT _TNCreate(HWND hWnd)
|
|
{
|
|
HWND hwndClock;
|
|
PTNPRIVDATA pTNPrivData;
|
|
|
|
hwndClock = ClockCtl_Create(hWnd, IDC_CLOCK, hinstCabinet);
|
|
if (!hwndClock)
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
pTNPrivData = (PTNPRIVDATA)LocalAlloc(LPTR, SIZEOF(TNPRIVDATA));
|
|
if (!pTNPrivData)
|
|
{
|
|
return(-1);
|
|
}
|
|
SetWindowLong(hWnd, 0, (LONG)pTNPrivData);
|
|
|
|
pTNPrivData->hwndToolTips = CreateWindowEx(WS_EX_TOPMOST, c_szSToolTipsClass, c_szNULL,
|
|
WS_POPUP | TTS_ALWAYSTIP,
|
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
|
NULL, NULL, hinstCabinet,
|
|
NULL);
|
|
|
|
pTNPrivData->hwndNotify = hWnd;
|
|
pTNPrivData->hwndClock = hwndClock;
|
|
pTNPrivData->hdpaIcons = DPA_Create(0);
|
|
if (!pTNPrivData->hdpaIcons)
|
|
{
|
|
return(-1);
|
|
}
|
|
pTNPrivData->himlIcons = ImageList_Create(
|
|
GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
|
|
ILC_MASK, 0, 1);
|
|
if (!pTNPrivData->himlIcons)
|
|
{
|
|
return(-1);
|
|
}
|
|
|
|
pTNPrivData->clBk = GetSysColor(COLOR_3DFACE);
|
|
ImageList_SetBkColor(pTNPrivData->himlIcons, pTNPrivData->clBk);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
** _TNDestroy
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
LRESULT _TNDestroy(PTNPRIVDATA pTNPrivData)
|
|
{
|
|
if (pTNPrivData)
|
|
{
|
|
|
|
if (pTNPrivData->hwndToolTips)
|
|
DestroyWindow(pTNPrivData->hwndToolTips);
|
|
|
|
if (pTNPrivData->hdpaIcons)
|
|
{
|
|
while (_TNDeleteNotify(pTNPrivData, 0))
|
|
{
|
|
// Continue while there are icondata's to delete
|
|
}
|
|
DPA_Destroy(pTNPrivData->hdpaIcons);
|
|
}
|
|
|
|
if (pTNPrivData->himlIcons)
|
|
{
|
|
ImageList_Destroy(pTNPrivData->himlIcons);
|
|
}
|
|
|
|
SetWindowLong(pTNPrivData->hwndNotify, 0, 0);
|
|
LocalFree((HLOCAL)pTNPrivData);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
** _TNPaint
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
LRESULT _TNPaint(PTNPRIVDATA pTNPrivData)
|
|
{
|
|
HDC hdc;
|
|
PAINTSTRUCT ps;
|
|
UINT xIcon, yIcon;
|
|
RECT rcClient;
|
|
int x, y, i;
|
|
PTNPRIVICON pTNPrivIcon;
|
|
int nIcons;
|
|
COLORREF clBk;
|
|
HWND hWnd = pTNPrivData->hwndNotify;
|
|
|
|
hdc = BeginPaint(hWnd, &ps);
|
|
|
|
clBk = GetSysColor(COLOR_3DFACE);
|
|
if (pTNPrivData->clBk != clBk)
|
|
{
|
|
pTNPrivData->clBk = clBk;
|
|
ImageList_SetBkColor(pTNPrivData->himlIcons, pTNPrivData->clBk);
|
|
}
|
|
|
|
GetClientRect(hWnd, &rcClient);
|
|
|
|
// Draw the edge right away to reduce flash
|
|
// DrawEdge(hdc, &rcClient, BDR_SUNKENOUTER, BF_RECT);
|
|
|
|
xIcon = GetSystemMetrics(SM_CXSMICON);
|
|
yIcon = GetSystemMetrics(SM_CYSMICON);
|
|
|
|
x = pTNPrivData->rNotifies.left;
|
|
y = pTNPrivData->rNotifies.top;
|
|
|
|
nIcons = DPA_GetPtrCount(pTNPrivData->hdpaIcons);
|
|
for (i=0; i<nIcons; )
|
|
{
|
|
pTNPrivIcon = DPA_FastGetPtr(pTNPrivData->hdpaIcons, i);
|
|
|
|
// Note that if uIMLIndex < 0, this will not paint anything
|
|
if (pTNPrivIcon->uIMLIndex != (UINT)-1)
|
|
ImageList_Draw(pTNPrivData->himlIcons,
|
|
pTNPrivIcon->uIMLIndex, hdc, x, y, 0);
|
|
x += xIcon + g_cxBorder;
|
|
|
|
++i;
|
|
if (i%pTNPrivData->nCols == 0)
|
|
{
|
|
y += yIcon + g_cyBorder;
|
|
x = pTNPrivData->rNotifies.left;
|
|
}
|
|
}
|
|
|
|
EndPaint(hWnd, &ps);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
** _TNCalcRects
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
* This is kind of strange: the RECT for the clock is exact, while the
|
|
* RECT for the icons is exact on the left and top, but adds an extra
|
|
* border on the right and bottom.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
UINT _TNCalcRects(PTNPRIVDATA pTNPrivData, int nMaxHorz, LPRECT prClock, LPRECT prNotifies)
|
|
{
|
|
UINT xIcon, yIcon;
|
|
UINT nCols, nRows;
|
|
LRESULT lRes;
|
|
|
|
xIcon = GetSystemMetrics(SM_CXSMICON);
|
|
yIcon = GetSystemMetrics(SM_CYSMICON);
|
|
|
|
lRes = SendMessage(pTNPrivData->hwndClock, WM_CALCMINSIZE, 0, 0);
|
|
prClock->right = LOWORD(lRes);
|
|
prClock->bottom = HIWORD(lRes);
|
|
|
|
// We need an g_cxBorder between each icon, plus a border between the
|
|
// icons and the clock, and the icons and the edge (if any icons)
|
|
prNotifies->right = DPA_GetPtrCount(pTNPrivData->hdpaIcons) * (xIcon+g_cxBorder);
|
|
if (prNotifies->right)
|
|
{
|
|
prNotifies->right += g_cxBorder;
|
|
}
|
|
|
|
// If there are no icons, or if the extent is wide enough,
|
|
// then we will just have one row of information
|
|
if (!prNotifies->right || nMaxHorz>=prNotifies->right+prClock->right)
|
|
{
|
|
if (prNotifies->right)
|
|
{
|
|
prNotifies->left = g_cxBorder;
|
|
prNotifies->top = g_cyBorder;
|
|
// right is already set
|
|
prNotifies->bottom = prNotifies->top + yIcon + g_cyBorder;
|
|
}
|
|
else
|
|
{
|
|
SetRectEmpty(prNotifies);
|
|
}
|
|
|
|
prClock->left = prNotifies->right;
|
|
prClock->top = 0;
|
|
prClock->right += prClock->left;
|
|
prClock->bottom += prClock->top;
|
|
|
|
nCols = DPA_GetPtrCount(pTNPrivData->hdpaIcons);
|
|
}
|
|
else
|
|
{
|
|
// Adjust for one border width around the icons
|
|
nMaxHorz -= 2*g_cxBorder;
|
|
|
|
// We need to fit at least one icon
|
|
if (nMaxHorz < (int)xIcon)
|
|
{
|
|
nMaxHorz = xIcon;
|
|
}
|
|
|
|
// Find the number of icons that will fit across, and thus
|
|
// the number of rows
|
|
nCols = (nMaxHorz+g_cxBorder)/(xIcon+g_cxBorder);
|
|
nRows = (DPA_GetPtrCount(pTNPrivData->hdpaIcons)+nCols-1)/nCols;
|
|
|
|
prNotifies->left = g_cxBorder;
|
|
prNotifies->top = prClock->bottom + g_cyBorder;
|
|
// Add the border around the edges
|
|
prNotifies->right = nCols*(xIcon+g_cxBorder) + g_cxBorder;
|
|
prNotifies->bottom = prNotifies->top
|
|
+ nRows*(yIcon+g_cyBorder) + g_cyBorder;
|
|
|
|
prClock->left = 0;
|
|
prClock->top = 0;
|
|
if (prClock->right && (prClock->right < prNotifies->right))
|
|
{
|
|
// Use the larger value to center properly
|
|
prClock->right = prNotifies->right;
|
|
}
|
|
// bottom is already set
|
|
}
|
|
|
|
if (prClock->bottom < g_cySize + g_cyEdge)
|
|
prClock->bottom = g_cySize + g_cyEdge;
|
|
|
|
// Add back the border around the whole window
|
|
OffsetRect(prClock, g_cxBorder, g_cyBorder);
|
|
OffsetRect(prNotifies, g_cxBorder, g_cyBorder);
|
|
|
|
return(nCols);
|
|
}
|
|
|
|
|
|
/*
|
|
** _TNCalcMinSize
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
LRESULT _TNCalcMinSize(PTNPRIVDATA pTNPrivData, int nMaxHorz)
|
|
{
|
|
RECT rTotal, rClock, rNotifies;
|
|
|
|
if (!(GetWindowLong(pTNPrivData->hwndClock, GWL_STYLE) & WS_VISIBLE) &&
|
|
!DPA_GetPtrCount(pTNPrivData->hdpaIcons)) {
|
|
ShowWindow(pTNPrivData->hwndNotify, SW_HIDE);
|
|
return 0L;
|
|
} else {
|
|
if (!IsWindowVisible(pTNPrivData->hwndNotify))
|
|
ShowWindow(pTNPrivData->hwndNotify, SW_SHOW);
|
|
}
|
|
|
|
pTNPrivData->nCols = _TNCalcRects(pTNPrivData, nMaxHorz, &rClock, &rNotifies);
|
|
|
|
UnionRect(&rTotal, &rClock, &rNotifies);
|
|
|
|
// this can happen if rClock's hidden width is 0;
|
|
// make sure the rTotal height is at least the clock's height.
|
|
// it can be smaller if the clock is hidden and thus has a 0 width
|
|
if ((rTotal.bottom - rTotal.top) < (rClock.bottom - rClock.top))
|
|
rTotal.bottom = rTotal.top + (rClock.bottom - rClock.top);
|
|
|
|
// Add on room for borders
|
|
return(MAKELRESULT(rTotal.right+g_cxBorder, rTotal.bottom+g_cyBorder));
|
|
}
|
|
|
|
|
|
/*
|
|
** _TNSize
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
LRESULT _TNSize(PTNPRIVDATA pTNPrivData)
|
|
{
|
|
RECT rTotal, rClock;
|
|
HWND hWnd = pTNPrivData->hwndNotify;
|
|
|
|
// use GetWindowRect because _TNCalcRects includes the borders
|
|
GetWindowRect(hWnd, &rTotal);
|
|
rTotal.right -= rTotal.left;
|
|
rTotal.bottom -= rTotal.top;
|
|
rTotal.left = rTotal.bottom = 0;
|
|
|
|
// Account for borders on the left and right
|
|
pTNPrivData->nCols = _TNCalcRects(pTNPrivData, rTotal.right,
|
|
&rClock, &pTNPrivData->rNotifies);
|
|
|
|
SetWindowPos(pTNPrivData->hwndClock, NULL, rClock.left, rClock.top,
|
|
rClock.right-rClock.left, rClock.bottom-rClock.top, SWP_NOZORDER);
|
|
|
|
_TNResetToolTipsRects(pTNPrivData);
|
|
|
|
return(0);
|
|
}
|
|
|
|
// returns BOOL if the lParam specifies a pos over the clock
|
|
extern BOOL IsPosInHwnd(LPARAM lParam, HWND hwnd);
|
|
|
|
#define _IsOverClock(pTNPrivdata, lParam) IsPosInHwnd(lParam, pTNPrivdata->hwndClock)
|
|
|
|
/*
|
|
** _TNIconFromPoint
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
* Note that a click on the C?BORDER after an icon yields a click on
|
|
* that icon. No big deal.
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
PTNPRIVICON _TNIconFromPoint(PTNPRIVDATA pTNPrivData, int x, int y, LPINT pnIcon)
|
|
{
|
|
UINT xIcon, yIcon;
|
|
int nCol, nRow, nIcon;
|
|
|
|
xIcon = GetSystemMetrics(SM_CXSMICON);
|
|
yIcon = GetSystemMetrics(SM_CYSMICON);
|
|
|
|
if (!pTNPrivData->nCols)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
x -= pTNPrivData->rNotifies.left;
|
|
nCol = x / (xIcon+g_cxBorder);
|
|
// Make sure that x is in bounds
|
|
if (x<0 || nCol>=pTNPrivData->nCols)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
y -= pTNPrivData->rNotifies.top;
|
|
nRow = y / (yIcon+g_cyBorder);
|
|
// Make sure that y is in bounds
|
|
if (y < 0)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
nIcon = pTNPrivData->nCols*nRow + nCol;
|
|
|
|
*pnIcon = nIcon;
|
|
// We will get NULL if we go off the end of the array
|
|
return(DPA_GetPtr(pTNPrivData->hdpaIcons, nIcon));
|
|
}
|
|
|
|
|
|
/*
|
|
** _TNMouseEvent
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
LRESULT _TNMouseEvent(PTNPRIVDATA pTNPrivData, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PTNPRIVICON pTNPrivIcon;
|
|
int nIcon;
|
|
|
|
if(pTNPrivData->hwndToolTips)
|
|
{
|
|
MSG msg;
|
|
|
|
msg.lParam = lParam;
|
|
msg.wParam = wParam;
|
|
msg.message = uMsg;
|
|
msg.hwnd = pTNPrivData->hwndNotify;
|
|
SendMessage(pTNPrivData->hwndToolTips, TTM_RELAYEVENT,
|
|
0, (LPARAM)(LPMSG)&msg);
|
|
}
|
|
|
|
pTNPrivIcon = _TNIconFromPoint(pTNPrivData, LOWORD(lParam), HIWORD(lParam), &nIcon);
|
|
if (!pTNPrivIcon)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
if (pTNPrivIcon->tnd.uCallbackMessage)
|
|
{
|
|
if (IsWindow(pTNPrivIcon->tnd.hWnd)) {
|
|
SendNotifyMessage(pTNPrivIcon->tnd.hWnd,
|
|
pTNPrivIcon->tnd.uCallbackMessage, pTNPrivIcon->tnd.uID,
|
|
uMsg);
|
|
} else {
|
|
_TNDeleteNotify(pTNPrivData, nIcon);
|
|
Tray_SizeWindows();
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
LRESULT _TNNotify(PTNPRIVDATA pTNPrivData, LPNMHDR lpNmhdr)
|
|
{
|
|
LPTOOLTIPTEXT pTtt;
|
|
PTNPRIVICON pTNPrivIcon;
|
|
|
|
switch (lpNmhdr->code)
|
|
{
|
|
|
|
case TTN_SHOW:
|
|
SetWindowPos(pTNPrivData->hwndToolTips,
|
|
HWND_TOP,
|
|
0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
break;
|
|
|
|
case TTN_NEEDTEXT:
|
|
pTtt = (LPTOOLTIPTEXT)lpNmhdr;
|
|
pTNPrivIcon = (PTNPRIVICON)pTtt->hdr.idFrom;
|
|
|
|
lstrcpyn(pTtt->lpszText, pTNPrivIcon->tnd.szTip,
|
|
ARRAYSIZE(pTtt->szText));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
LRESULT CALLBACK _TNWinIniChange(PTNPRIVDATA pTNPrivData, UINT uMsg,
|
|
WPARAM wParam, LPARAM lParam)
|
|
{
|
|
|
|
_TNCheckAndResizeImages(pTNPrivData);
|
|
|
|
return(pTNPrivData && pTNPrivData->hwndClock &&
|
|
SendMessage(pTNPrivData->hwndClock,
|
|
uMsg, wParam, lParam));
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
LRESULT CALLBACK TrayNotifyWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PTNPRIVDATA pTNPrivData;
|
|
|
|
pTNPrivData = (PTNPRIVDATA)GetWindowLong(hWnd, 0);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_CREATE:
|
|
return _TNCreate(hWnd);
|
|
case WM_DESTROY:
|
|
return _TNDestroy(pTNPrivData);
|
|
case WM_PAINT:
|
|
return _TNPaint(pTNPrivData);
|
|
|
|
case WM_CALCMINSIZE:
|
|
return _TNCalcMinSize(pTNPrivData, wParam);
|
|
|
|
// The clock needs to see certain messages forwarded to him.
|
|
case WM_TIMECHANGE:
|
|
case WM_WININICHANGE:
|
|
return _TNWinIniChange(pTNPrivData, uMsg, wParam, lParam);
|
|
|
|
|
|
case WM_NCHITTEST:
|
|
return(_IsOverClock(pTNPrivData, lParam) ? HTTRANSPARENT : HTCLIENT);
|
|
|
|
|
|
case WM_LBUTTONDOWN:
|
|
case WM_MBUTTONDOWN:
|
|
case WM_RBUTTONDOWN:
|
|
case WM_MOUSEMOVE:
|
|
case WM_LBUTTONUP:
|
|
case WM_MBUTTONUP:
|
|
case WM_RBUTTONUP:
|
|
case WM_LBUTTONDBLCLK:
|
|
case WM_MBUTTONDBLCLK:
|
|
case WM_RBUTTONDBLCLK:
|
|
if (_TNMouseEvent(pTNPrivData, uMsg, wParam, lParam) && (uMsg == WM_RBUTTONUP))
|
|
break;
|
|
goto DoDefault; // we need to pass these through to defwndproc for user to process WM_CONTEXTMENU
|
|
|
|
case WM_NOTIFY:
|
|
return(_TNNotify(pTNPrivData, (LPNMHDR)lParam));
|
|
|
|
case TNM_GETCLOCK:
|
|
return (LRESULT)pTNPrivData->hwndClock;
|
|
|
|
case TNM_TRAYHIDE:
|
|
if (IsWindowVisible(pTNPrivData->hwndClock))
|
|
SendMessage(pTNPrivData->hwndClock, TCM_TRAYHIDE, 0, lParam);
|
|
break;
|
|
|
|
case TNM_HIDECLOCK:
|
|
ShowWindow(pTNPrivData->hwndClock, lParam ? SW_HIDE : SW_SHOW);
|
|
if (!lParam) {
|
|
PostMessage(pTNPrivData->hwndClock, TCM_KICKSTART, 0, 0);
|
|
}
|
|
break;
|
|
case WM_SIZE:
|
|
_TNSize(pTNPrivData);
|
|
case WM_MOVE:
|
|
// Always invalidate on a move or resize
|
|
InvalidateRect(hWnd, NULL, TRUE);
|
|
default:
|
|
DoDefault:
|
|
return (DefWindowProc(hWnd, uMsg, wParam, lParam));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#if 0
|
|
/*
|
|
** _TNGetIconRect
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
void _TNGetIconRect(PTNPRIVDATA pTNPrivData, int nIcon, LPRECT prIcon)
|
|
{
|
|
UINT xIcon, yIcon;
|
|
|
|
xIcon = GetSystemMetrics(SM_CXSMICON);
|
|
yIcon = GetSystemMetrics(SM_CYSMICON);
|
|
|
|
if (!pTNPrivData->nCols)
|
|
{
|
|
SetRectEmpty(prIcon);
|
|
return;
|
|
}
|
|
|
|
prIcon->left = (nIcon%pTNPrivData->nCols) * (xIcon+g_cxBorder);
|
|
prIcon->top = (nIcon/pTNPrivData->nCols) * (yIcon+g_cyBorder);
|
|
prIcon->right = prIcon->left + xIcon+g_cxBorder;
|
|
prIcon->bottom = prIcon->top + yIcon+g_cyBorder;
|
|
|
|
OffsetRect(prIcon, pTNPrivData->rNotifies.left, pTNPrivData->rNotifies.top);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
** TrayNotify
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
LRESULT TrayNotify(HWND hwndNotify, HWND hwndFrom, PCOPYDATASTRUCT pcds)
|
|
{
|
|
int nIcon;
|
|
PTNPRIVDATA pTNPrivData;
|
|
RECT rNotifies;
|
|
PTRAYNOTIFYDATA pTND;
|
|
PNOTIFYICONDATA pNID;
|
|
BOOL bErase = TRUE;
|
|
|
|
if (!hwndNotify || !pcds)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
pTNPrivData = (PTNPRIVDATA)GetWindowLong(hwndNotify, 0);
|
|
|
|
if (pcds->cbData < SIZEOF(TRAYNOTIFYDATA))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// We'll add a signature just in case
|
|
pTND = (PTRAYNOTIFYDATA)pcds->lpData;
|
|
if (pTND->dwSignature != NI_SIGNATURE)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
pNID = &pTND->nid;
|
|
if (pNID->cbSize<SIZEOF(NOTIFYICONDATA))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
rNotifies = pTNPrivData->rNotifies;
|
|
|
|
switch (pTND->dwMessage)
|
|
{
|
|
case NIM_ADD:
|
|
if (_TNFindNotify(pTNPrivData, pNID) >= 0)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!_TNInsertNotify(pTNPrivData, pNID, 0x7fff))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
break;
|
|
|
|
case NIM_MODIFY:
|
|
nIcon = _TNFindNotify(pTNPrivData, pNID);
|
|
if (nIcon < 0)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!_TNModifyNotify(pTNPrivData, pNID, nIcon))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
bErase = FALSE;
|
|
break;
|
|
|
|
case NIM_DELETE:
|
|
nIcon = _TNFindNotify(pTNPrivData, pNID);
|
|
if (nIcon < 0)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
_TNDeleteNotify(pTNPrivData, nIcon);
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
// Invalidate the old and new rectangle that includes all the icons
|
|
InvalidateRect(hwndNotify, &rNotifies, bErase);
|
|
_TNSize(pTNPrivData);
|
|
InvalidateRect(hwndNotify, &pTNPrivData->rNotifies, bErase);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/*
|
|
** TrayNotifyCreate
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* RETURNS:
|
|
*
|
|
*/
|
|
|
|
HWND TrayNotifyCreate(HWND hwndParent, UINT uID, HINSTANCE hInst)
|
|
{
|
|
WNDCLASSEX wc;
|
|
|
|
wc.cbSize = SIZEOF(WNDCLASSEX);
|
|
|
|
if (!GetClassInfoEx(hInst, c_szTrayNotify, &wc))
|
|
{
|
|
wc.lpszClassName = c_szTrayNotify;
|
|
wc.style = CS_DBLCLKS;
|
|
wc.lpfnWndProc = TrayNotifyWndProc;
|
|
wc.hInstance = hInst;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
|
|
wc.lpszMenuName = NULL;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = SIZEOF(PTNPRIVDATA);
|
|
wc.hIconSm = NULL;
|
|
|
|
if (!RegisterClassEx(&wc))
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
if (!ClockCtl_Class(hInst))
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
}
|
|
|
|
return(CreateWindowEx(WS_EX_STATICEDGE, c_szTrayNotify,
|
|
NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | WS_CLIPCHILDREN, 0, 0, 0, 0,
|
|
hwndParent, (HMENU)uID, hInst, NULL));
|
|
}
|