Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1017 lines
27 KiB

/*
** STATUS.C
**
** Status bar code
**
*/
#include "ctlspriv.h"
#define SBT_NORMAL 0xf000
#define SBT_NULL 0x0000 /* Some code depends on this being 0 */
#define SBT_ALLTYPES 0xf000
#define MAXPARTS 256
// JAPANBEGIN
TCHAR szSystem[] = TEXT("System");
// JAPANEND
TCHAR szSansSerif[] = TEXT("MS Sans Serif");
TCHAR szNull[] = TEXT("");
static WCHAR szStatusClassW[] = STATUSCLASSNAMEW;
static CCHAR szStatusClassA[] = STATUSCLASSNAMEA;
static TCHAR szDesktop[] = TEXT("Desktop");
static TCHAR szStatFaceHeight[] = TEXT("StatusBarFaceHeight");
static TCHAR szStatFaceName[] = TEXT("StatusBarFaceName");
// Static function bugs
#define Static
Static VOID
NewFont(HWND hWnd, PSTATUSINFO pStatusInfo,
HFONT hNewFont)
{
HFONT hOldFont;
BOOL bDelFont;
TCHAR szFaceName[32];
TEXTMETRIC tm;
HDC hDC;
INT nHeight;
hOldFont = pStatusInfo->hStatFont;
bDelFont = pStatusInfo->bDefFont;
hDC = GetDC(hWnd);
if (hNewFont) {
pStatusInfo->hStatFont = hNewFont;
pStatusInfo->bDefFont = FALSE;
} else {
if (bDelFont) {
// I will reuse the default font, so don't delete it later
hNewFont = pStatusInfo->hStatFont;
bDelFont = FALSE;
} else {
nHeight = GetProfileInt(szDesktop, szStatFaceHeight, 10);
if (bJapan) {
GetProfileString(szDesktop, szStatFaceName, szSystem,
szFaceName, COUNTOF(szFaceName));
hNewFont =
CreateFont(-nHeight * GetDeviceCaps(hDC, LOGPIXELSY) / 72,
0, 0, 0, 400, 0, 0, 0, SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
VARIABLE_PITCH | FF_SWISS, szFaceName);
} else {
GetProfileString(szDesktop, szStatFaceName, UNICODE_FONT_NAME,
szFaceName, COUNTOF(szFaceName));
hNewFont =
CreateFont(-nHeight * GetDeviceCaps(hDC, LOGPIXELSY) / 72,
0, 0, 0, 400, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
VARIABLE_PITCH | FF_SWISS, szFaceName);
}
pStatusInfo->hStatFont = hNewFont;
pStatusInfo->bDefFont = (BOOL)hNewFont; // I'm cheating here!
}
}
// We delete the old font after creating the new one in case they are
// the same; this should help GDI a little
if (bDelFont)
DeleteObject(hOldFont);
// HACK! Pass in -1 to just delete the old font
if (hNewFont != (HFONT)-1) {
hOldFont = 0;
if (hNewFont)
hOldFont = SelectObject(hDC, hNewFont);
GetTextMetrics(hDC, &tm);
if (hOldFont)
SelectObject(hDC, hOldFont);
pStatusInfo->nFontHeight = tm.tmHeight + tm.tmInternalLeading;
}
ReleaseDC(hWnd, hDC);
}
Static PSTATUSINFO
AllocDefInfo(VOID)
{
PSTATUSINFO pStatusInfo;
pStatusInfo = (PSTATUSINFO)LocalAlloc(LMEM_FIXED, sizeof(STATUSINFO));
if (!pStatusInfo)
return(NULL);
pStatusInfo->hStatFont = NULL;
pStatusInfo->bDefFont = FALSE;
pStatusInfo->nFontHeight = 0;
pStatusInfo->nMinHeight = 0;
pStatusInfo->nBorderX = 0;
pStatusInfo->nBorderY = 0;
pStatusInfo->nBorderPart = 0;
pStatusInfo->sSimple.uType = SBT_NOSIMPLE | SBT_NULL;
pStatusInfo->sSimple.right = -1;
pStatusInfo->nParts = 1;
pStatusInfo->sInfo[0].uType = SBT_NULL;
pStatusInfo->sInfo[0].right = -1;
return(pStatusInfo);
}
// We should send messages instead of calling things directly so we can
// be subclassed more easily.
Static LRESULT
InitStatusWnd(HWND hWnd, LPCREATESTRUCT lpCreate)
{
PSTATUSINFO pStatusInfo;
int nBorders[3] = {-1, -1, -1} ;
// Get the status info struct; abort if it does not exist, otherwise
// save it in the window structure
pStatusInfo = AllocDefInfo();
if (!pStatusInfo)
return(-1);
SetWindowLong(hWnd, GWL_PSTATUSINFO, (LONG)pStatusInfo);
// Save the window text in our struct, and let USER store the NULL string
SendMessage(hWnd, SB_SETTEXT, 0, (LPARAM)lpCreate->lpszName);
lpCreate->lpszName = szNull;
SendMessage(hWnd, WM_SETFONT, 0, 0L);
SendMessage(hWnd, SB_SETBORDERS, 0, (LPARAM)(LPINT)nBorders);
return(0);
}
void WINAPI
DrawStatusTextA(HDC hDC, LPRECT lprc, LPCSTR szText, UINT uFlags)
{
INT cch;
LPWSTR lpw;
cch = lstrlenA(szText) + 1;
lpw = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, ByteCountOf(cch));
if (!lpw) {
#ifdef DEBUG
OutputDebugString(TEXT("Alloc failed: DrawStatusTextA\r\n"));
#endif
return;
}
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szText, cch, lpw, cch);
DrawStatusTextW(hDC, lprc, lpw, uFlags);
LocalFree((LPVOID)lpw);
}
void WINAPI
DrawStatusTextW(HDC hDC, LPRECT lprc, LPCWSTR szText, UINT uFlags)
{
INT len;
INT nBorderX, nBorderY;
HBRUSH hHiliteBrush = NULL, hShadowBrush = NULL, hFaceBrush = NULL;
HBRUSH hOldBrush;
COLORREF crFaceColor, crTextColor, crBkColor;
UINT uOpts;
BOOL bNull;
INT nOldMode;
INT i, left;
LPWSTR lpTab, lpNext;
SIZE Size;
// Save these for later use
nBorderX = GetSystemMetrics(SM_CXBORDER);
nBorderY = GetSystemMetrics(SM_CYBORDER);
// Create the three brushes we need. If the button face is a solid
// color, then we will just draw in opaque, instead of using a
// brush to avoid the flash
if (!(uFlags&SBT_NOBORDERS)) {
hHiliteBrush = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT));
hShadowBrush = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
if (uFlags&SBT_POPOUT) {
// Switch the brushes to make it pop out
hOldBrush = hHiliteBrush;
hHiliteBrush = hShadowBrush;
hShadowBrush = hOldBrush;
}
}
crFaceColor = GetSysColor(COLOR_BTNFACE);
if (GetNearestColor(hDC, crFaceColor) == crFaceColor ||
!(hFaceBrush=CreateSolidBrush(crFaceColor))) {
uOpts = ETO_CLIPPED | ETO_OPAQUE;
nOldMode = SetBkMode(hDC, OPAQUE);
} else {
uOpts = ETO_CLIPPED;
nOldMode = SetBkMode(hDC, TRANSPARENT);
}
crTextColor = SetTextColor(hDC, GetSysColor(COLOR_BTNTEXT));
crBkColor = SetBkColor(hDC, crFaceColor);
// Draw the hilites
if (hHiliteBrush) {
hOldBrush = SelectObject(hDC, hHiliteBrush);
if (hOldBrush) {
PatBlt (hDC, lprc->right, lprc->bottom,
-(lprc->right-lprc->left-nBorderX), -nBorderY, PATCOPY);
PatBlt (hDC, lprc->right, lprc->bottom,
-nBorderX, -(lprc->bottom-lprc->top-nBorderY), PATCOPY);
SelectObject(hDC, hOldBrush);
}
}
if (hShadowBrush) {
hOldBrush = SelectObject(hDC, hShadowBrush);
if (hOldBrush) {
PatBlt (hDC, lprc->left, lprc->top,
lprc->right-lprc->left, nBorderY, PATCOPY);
PatBlt (hDC, lprc->left, lprc->top,
nBorderX, lprc->bottom-lprc->top, PATCOPY);
SelectObject(hDC, hOldBrush);
}
}
// We need to adjust the rect for the ExtTextOut, and then
// adjust it back
if (!(uFlags&SBT_NOBORDERS)) // andrewbe
InflateRect(lprc, -nBorderX, -nBorderY);
if (hFaceBrush) {
hOldBrush = SelectObject(hDC, hFaceBrush);
if (hOldBrush) {
PatBlt (hDC, lprc->left, lprc->top,
lprc->right-lprc->left, lprc->bottom-lprc->top, PATCOPY);
SelectObject(hDC, hOldBrush);
}
}
for (i = 0, lpNext = szText, bNull = FALSE; i < 3; ++i) {
// Optimize for NULL left or center strings
if (*lpNext == TEXT('\t') && i <= 1) {
++lpNext;
continue;
}
// Determine the end of the current string
for (lpTab = lpNext; ; lpTab = CharNext(lpTab)) {
if (!*lpTab) {
bNull = TRUE;
break;
} else if (*lpTab == TEXT('\t'))
break;
}
*lpTab = TEXT('\0');
len = lstrlen(lpNext);
// i=0 means left, 1 means center, and 2 means right justified text
switch (i) {
case 0:
left = lprc->left + 2*nBorderX;
break;
case 1:
(VOID) GetTextExtentPoint(hDC, lpNext, len, &Size);
left = (lprc->left + lprc->right + Size.cx) /2;
break;
default:
(VOID) GetTextExtentPoint(hDC, lpNext, len, &Size);
left = lprc->right - 2*nBorderX - Size.cx;
break;
}
ExtTextOut(hDC, left, lprc->top, uOpts, lprc, lpNext, len, NULL);
// Now that we have drawn text once, take off the OPAQUE flag
uOpts = ETO_CLIPPED;
if (bNull)
break;
*lpTab = TEXT('\t');
lpNext = lpTab + 1;
}
if (!(uFlags & SBT_NOBORDERS)) // andrewbe
InflateRect(lprc, nBorderX, nBorderY);
SetTextColor(hDC, crTextColor);
SetBkColor(hDC, crBkColor);
SetBkMode(hDC, nOldMode);
if (hHiliteBrush)
DeleteObject(hHiliteBrush);
if (hShadowBrush)
DeleteObject(hShadowBrush);
if (hFaceBrush)
DeleteObject(hFaceBrush);
}
VOID
PaintStatusWnd(HWND hWnd, PSTATUSINFO pStatusInfo,
PSTRINGINFO pStringInfo, int nParts, int nBorderX, BOOL bHeader)
{
HBRUSH hHiliteBrush, hOldBrush;
DRAWITEMSTRUCT di;
PAINTSTRUCT ps;
RECT rc;
INT nSaveRight;
HFONT hOldFont = NULL;
INT i, j;
UINT uType;
BeginPaint(hWnd, &ps);
// Get the client rect and inset the top and bottom. Then set
// up the right side for entry into the loop
GetClientRect(hWnd, &rc);
if (!(GetWindowLong(hWnd, GWL_STYLE)&CCS_NOHILITE)) {
hHiliteBrush = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT));
if (hHiliteBrush) {
hOldBrush = SelectObject(ps.hdc, hHiliteBrush);
if (hOldBrush) {
PatBlt (ps.hdc, 0, 0, rc.right, GetSystemMetrics(SM_CYBORDER),
PATCOPY);
SelectObject(ps.hdc, hOldBrush);
}
DeleteObject(hHiliteBrush);
}
// Hack for headers:
// This highlight seems to be integrated into the border for status bars,
// but not for headers, which don't normally have a border.
// Previously this was corrected for by calling InflateRect in
// DrawStatusText, but that was wrong for headers, since it left a
// borderwidth of pels unpainted at the bottom of the border,
// which shows up when you force a repaint by calling InvalidateRect
// with fErase = FALSE (to avoid flickering).
// (andrewbe)
if (bHeader)
rc.top += GetSystemMetrics(SM_CYBORDER);
}
rc.top += pStatusInfo->nBorderY;
rc.bottom -= pStatusInfo->nBorderY;
nSaveRight = rc.right;
rc.right = nBorderX - pStatusInfo->nBorderPart;
if (pStatusInfo->hStatFont)
hOldFont = SelectObject(ps.hdc, pStatusInfo->hStatFont);
for (i = 0; i < nParts; ++i, ++pStringInfo) {
rc.left = rc.right + pStatusInfo->nBorderPart;
// Check whether any of the "later" partitions are to the left of
// this one (but don't check the last part), for headers only.
if (bHeader) {
for (j = nParts - i - 2; j >= 0; --j)
if (pStringInfo->right < rc.left)
break;
if (j >= 0)
continue;
}
rc.right = pStringInfo->right;
if (rc.right < 0)
rc.right = nSaveRight - nBorderX;
if (rc.right < rc.left || !RectVisible(ps.hdc, &rc))
continue;
uType = pStringInfo->uType;
if ((uType&SBT_ALLTYPES) == SBT_NORMAL) {
DrawStatusText(ps.hdc, &rc,
pStringInfo->pString, uType);
} else {
DrawStatusText(ps.hdc, &rc, szNull, uType);
if (uType&SBT_OWNERDRAW) {
di.CtlID = GetWindowLong(hWnd, GWL_ID);
di.itemID = i;
di.hwndItem = hWnd;
di.hDC = ps.hdc;
di.rcItem = rc;
InflateRect (&di.rcItem, -GetSystemMetrics(SM_CXBORDER),
-GetSystemMetrics(SM_CYBORDER));
di.itemData = pStringInfo->pString;
SaveDC(ps.hdc);
IntersectClipRect(ps.hdc, di.rcItem.left, di.rcItem.top,
di.rcItem.right, di.rcItem.bottom);
SendMessage (GetParent(hWnd), WM_DRAWITEM, di.CtlID,
(LPARAM)(LPTSTR)&di);
RestoreDC(ps.hdc, -1);
}
}
}
if (hOldFont)
SelectObject(ps.hdc, hOldFont);
EndPaint(hWnd, &ps);
}
Static BOOL
SetStatusText(HWND hWnd, PSTRINGINFO pStringInfo,
UINT uPart, LPTSTR lpStr)
{
LPTSTR pString;
UINT uiLen;
INT nPart;
RECT rc;
nPart = LOBYTE(uPart);
// Note it is up to the app the dispose of the previous itemData for
// SBT_OWNERDRAW
if ((pStringInfo->uType&SBT_ALLTYPES) == SBT_NORMAL)
LocalFree((HLOCAL)pStringInfo->pString);
// Set to the NULL string in case anything goes wrong
pStringInfo->uType = uPart & 0xff00;
pStringInfo->uType &= ~SBT_ALLTYPES;
pStringInfo->uType |= SBT_NULL;
// Invalidate the rect of this pane
GetClientRect(hWnd, &rc);
if (nPart)
rc.left = pStringInfo[-1].right;
if (pStringInfo->right > 0)
rc.right = pStringInfo->right;
InvalidateRect(hWnd, &rc, FALSE);
switch (uPart&SBT_ALLTYPES) {
case 0:
// If lpStr==NULL, we have the NULL string
if (lpStr) {
uiLen = (WORD)lstrlen(lpStr);
if (uiLen) {
pStringInfo->pString = (LPTSTR) LocalAlloc(LPTR, ByteCountOf(uiLen+1));
if (pStringInfo->pString) {
pStringInfo->uType |= SBT_NORMAL;
// Copy the string
pString = pStringInfo->pString;
lstrcpy(pString, lpStr);
// Replace unprintable characters (like CR/LF) with spaces
for ( ; *pString;
pString = CharNext(pString))
//if ((unsigned TCHAR)(*pString) < TEXT(' ') && *pString != TEXT('\t'))
if ((*pString) < TEXT(' ') && *pString != TEXT('\t'))
*pString = TEXT(' ');
} else {
// We return FALSE to indicate there was an error setting
// the string
return(FALSE);
}
}
}
// No more hiword/loword, this code is non-sensical in 32bit
/*
else if (lpStr) {
// We don't allow this anymore; the app needs to set the ownerdraw
// bit for ownerdraw.
return(FALSE);
}
*/
break;
case SBT_OWNERDRAW:
pStringInfo->uType |= SBT_OWNERDRAW;
pStringInfo->pString = lpStr;
break;
default:
return(FALSE);
}
return(TRUE);
}
Static BOOL
SetStatusParts(HWND hWnd, PSTATUSINFO pStatusInfo,
INT nParts, LPINT lpInt)
{
INT i;
PSTATUSINFO pStatusTemp;
PSTRINGINFO pStringInfo;
BOOL bRedraw = FALSE;
if (nParts != pStatusInfo->nParts) {
bRedraw = TRUE;
// Note that if nParts > pStatusInfo->nParts, this loop
// does nothing
for (i = pStatusInfo->nParts - nParts,
pStringInfo = &pStatusInfo->sInfo[nParts]; i > 0;
--i, ++pStringInfo) {
if ((pStringInfo->uType&SBT_ALLTYPES) == SBT_NORMAL)
LocalFree((HLOCAL)pStringInfo->pString);
pStringInfo->uType = SBT_NULL;
}
// Realloc to the new size and store the new pointer
pStatusTemp = (PSTATUSINFO)LocalReAlloc((HLOCAL)pStatusInfo,
sizeof(STATUSINFO) + (nParts-1) * sizeof(STRINGINFO),
LMEM_MOVEABLE);
if (!pStatusTemp)
return(FALSE);
pStatusInfo = pStatusTemp;
SetWindowLong(hWnd, GWL_PSTATUSINFO, (LONG)pStatusInfo);
// Note that if nParts < pStatusInfo->nParts, this loop
// does nothing
for (i = nParts - pStatusInfo->nParts,
pStringInfo = &pStatusInfo->sInfo[pStatusInfo->nParts]; i > 0;
--i, ++pStringInfo)
pStringInfo->uType = SBT_NULL;
pStatusInfo->nParts = nParts;
}
for (i = 0, pStringInfo = pStatusInfo->sInfo; i < nParts;
++i, ++pStringInfo, ++lpInt) {
if (pStringInfo->right != *lpInt) {
bRedraw = TRUE;
pStringInfo->right = *lpInt;
}
}
// Only redraw if necesary (if the number of parts has changed or
// a border has changed)
if (bRedraw)
InvalidateRect(hWnd, NULL, TRUE);
return(TRUE);
}
// Note that HeaderWndProc calls this, so make sure they are in sync.
LRESULT CALLBACK
StatusWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
PSTATUSINFO pStatusInfo;
pStatusInfo = (PSTATUSINFO)GetWindowLong(hWnd, GWL_PSTATUSINFO);
switch (uMessage) {
case WM_CREATE:
return(InitStatusWnd(hWnd, (LPCREATESTRUCT)lParam));
case WM_DESTROY:
if (pStatusInfo) {
INT i;
PSTRINGINFO pStringInfo;
NewFont(hWnd, pStatusInfo, (HFONT)-1);
for (i = pStatusInfo->nParts - 1, pStringInfo = pStatusInfo->sInfo;
i >= 0; --i, ++pStringInfo) {
if ((pStringInfo->uType&SBT_ALLTYPES) == SBT_NORMAL)
LocalFree((HLOCAL)pStringInfo->pString);
}
if ((pStatusInfo->sSimple.uType&SBT_ALLTYPES) == SBT_NORMAL)
LocalFree((HLOCAL)pStatusInfo->sSimple.pString);
LocalFree((HLOCAL)pStatusInfo);
SetWindowLong(hWnd, GWL_PSTATUSINFO, 0L);
}
break;
case WM_SETTEXT:
wParam = 0;
#ifdef DEBUG
OutputDebugString(TEXT("Please use SB_SETTEXT, NOW! \n\r"));
#endif
return(FALSE);
// Fall through
case SB_SETTEXTW:
case SB_SETTEXTA:
if (!pStatusInfo)
return(FALSE);
// This is the "simple" status bar pane
if (LOBYTE(wParam) == 0xff) {
UINT uSimple;
BOOL bRet;
// Note that we do not allow OWNERDRAW for a "simple" status bar
if (wParam & SBT_OWNERDRAW)
return(FALSE);
uSimple = pStatusInfo->sSimple.uType;
if (uMessage == SB_SETTEXTW)
bRet = SetStatusText (hWnd, &pStatusInfo->sSimple,
wParam & 0xff00, (LPTSTR)lParam);
else {
LPTSTR lpTemp = NULL;
INT cch;
cch = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, (LPSTR)lParam,
-1, lpTemp, 0);
if (!(lpTemp = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, ByteCountOf(cch+1)))) {
#ifdef DEBUG
OutputDebugString(TEXT("Alloc failed: SB_SETTEXTA\r\n"));
#endif
return(FALSE);
}
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, (LPSTR)lParam,
-1, lpTemp, cch);
bRet = SetStatusText(hWnd, &pStatusInfo->sSimple,
wParam & 0xff00, lpTemp);
LocalFree(lpTemp);
}
pStatusInfo->sSimple.uType |= (uSimple & 0x00ff);
return(bRet);
}
if ((UINT)pStatusInfo->nParts <= (UINT)LOBYTE(wParam))
return(FALSE);
if (uMessage == SB_SETTEXTW)
return(SetStatusText (hWnd, &pStatusInfo->sInfo[LOBYTE(wParam)],
wParam, (LPTSTR)lParam));
else {
BOOL bTemp;
LPWSTR lpTemp = NULL;
INT cch;
cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPSTR)lParam,
-1, lpTemp, 0);
if (!(lpTemp = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, ByteCountOf(cch+1)))) {
#ifdef DEBUG
OutputDebugString(TEXT("Alloc failed: SB_SETTEXTA\r\n"));
#endif
return(FALSE);
}
MultiByteToWideChar (CP_ACP,MB_PRECOMPOSED,(LPSTR)lParam,
-1, lpTemp, cch);
bTemp = SetStatusText(hWnd, &pStatusInfo->sInfo[LOBYTE(wParam)],
wParam, lpTemp);
return(bTemp);
}
case WM_GETTEXT:
uMessage = SB_GETTEXT;
#ifdef DEBUG
OutputDebugString(TEXT("Please use SB_GETTEXT, NOW! \n\r"));
#endif
return(FALSE) ;
// Fall through
case WM_GETTEXTLENGTH:
wParam = 0;
// Fall through
case SB_GETTEXTA:
case SB_GETTEXTW:
case SB_GETTEXTLENGTH:
{
UINT uType;
LPWSTR pString;
BOOL fDefCharUsed;
LPSTR pStringA;
INT cchpStringA;
UINT uiLen;
// We assume the buffer is large enough to hold the string, just
// as listboxes do; the app should call SB_GETTEXTLEN first
if (!pStatusInfo || (UINT)pStatusInfo->nParts <= wParam)
return(0);
uType = pStatusInfo->sInfo[wParam].uType;
pString = pStatusInfo->sInfo[wParam].pString;
if (uMessage == SB_GETTEXTA) {
cchpStringA = lstrlen(pString) + 1;
if (!(pStringA = (LPSTR)LocalAlloc(LMEM_ZEROINIT, cchpStringA))) {
#ifdef DEBUG
OutputDebugString(TEXT("failed Alloc: SB_GETTEXTW\n\r"));
#endif
return(FALSE) ;
}
WideCharToMultiByte(CP_ACP, 0, pString, -1, pStringA, cchpStringA,
NULL, &fDefCharUsed);
}
if ((uType&SBT_ALLTYPES) == SBT_NORMAL) {
if (uMessage == SB_GETTEXTW && lParam)
lstrcpy((LPTSTR)lParam, pString);
else if (uMessage==SB_GETTEXTA && lParam)
lstrcpyA((LPSTR)lParam, pStringA);
uiLen = lstrlen(pString);
// Set this back to 0 to return to the app
uType &= ~SBT_ALLTYPES;
} else {
if (uMessage==SB_GETTEXTW && lParam)
*(LPTSTR)lParam = TEXT('\0');
else if (uMessage==SB_GETTEXTA && lParam)
*(LPSTR)lParam = '\0';
uiLen = 0;
if (uMessage == SB_GETTEXTW && (uType&SBT_ALLTYPES) == SBT_OWNERDRAW)
return(pString);
if (uMessage == SB_GETTEXTA && (uType&SBT_ALLTYPES) == SBT_OWNERDRAW)
return(pStringA);
}
return(MAKELONG(LOWORD(uiLen), uType));
}
case SB_SETPARTS:
if (!pStatusInfo || !wParam || wParam>MAXPARTS)
return(FALSE);
return(SetStatusParts(hWnd, pStatusInfo, wParam, (LPINT)lParam));
case SB_GETPARTS:
{
PSTRINGINFO pStringInfo;
LPINT lpInt;
if (!pStatusInfo)
return(0);
// Fill in the lesser of the number of entries asked for or
// the number of entries there are
if (wParam > (WPARAM)pStatusInfo->nParts)
wParam = pStatusInfo->nParts;
for (pStringInfo = pStatusInfo->sInfo, lpInt = (LPINT)lParam;
wParam > 0; --wParam, ++pStringInfo, ++lpInt)
*lpInt = pStringInfo->right;
// Always return the number of actual entries
return(pStatusInfo->nParts);
}
case SB_SETBORDERS:
{
INT nBorder;
LPINT lpInt;
if (!pStatusInfo)
return(FALSE);
lpInt = (LPINT)lParam;
nBorder = *lpInt++;
pStatusInfo->nBorderX = nBorder < 0 ? 8 * GetSystemMetrics(SM_CXBORDER)
: nBorder;
nBorder = *lpInt++;
pStatusInfo->nBorderY = nBorder < 0 ? 2 * GetSystemMetrics(SM_CYBORDER)
: nBorder;
nBorder = *lpInt;
pStatusInfo->nBorderPart = nBorder < 0 ? pStatusInfo->nBorderX
: nBorder;
return(TRUE);
}
case SB_GETBORDERS:
{
LPINT lpInt;
if (!pStatusInfo)
return(FALSE);
lpInt = (LPINT)lParam;
*lpInt++ = pStatusInfo->nBorderX;
*lpInt++ = pStatusInfo->nBorderY;
*lpInt++ = pStatusInfo->nBorderPart;
return(TRUE);
}
case SB_SETMINHEIGHT:
if (!pStatusInfo)
return(FALSE);
pStatusInfo->nMinHeight = wParam + 2*GetSystemMetrics(SM_CYBORDER);
break;
case SB_SIMPLE:
{
BOOL bInvalidate = FALSE;
if (!pStatusInfo)
return(FALSE);
if (wParam) {
if ((pStatusInfo->sSimple.uType&SBT_NOSIMPLE) != 0) {
pStatusInfo->sSimple.uType &= ~SBT_NOSIMPLE;
bInvalidate = TRUE;
}
} else {
if ((pStatusInfo->sSimple.uType&SBT_NOSIMPLE) != SBT_NOSIMPLE) {
pStatusInfo->sSimple.uType |= SBT_NOSIMPLE;
bInvalidate = TRUE;
}
}
if (bInvalidate)
InvalidateRect(hWnd, NULL, TRUE);
break;
}
case WM_SETFONT:
if (!pStatusInfo)
return(FALSE);
NewFont(hWnd, pStatusInfo, (HFONT)wParam);
if (lParam) {
InvalidateRect(hWnd, NULL, FALSE);
UpdateWindow(hWnd);
}
return(TRUE);
case WM_GETFONT:
if (!pStatusInfo)
return(0);
// No more word typecast in the middle
return((LRESULT)pStatusInfo->hStatFont);
case WM_SIZE:
{
INT nHeight;
RECT rc;
HWND hwndParent;
if (!pStatusInfo)
return(0);
GetWindowRect(hWnd, &rc);
rc.right -= rc.left;
rc.bottom -= rc.top;
// If there is no parent, then this is a top level window
hwndParent = GetParent(hWnd);
if (hwndParent)
ScreenToClient(hwndParent, (LPPOINT)&rc);
// Use the font height. Add to that twice the X border, and the
// window borders
nHeight = pStatusInfo->nFontHeight;
if (nHeight < pStatusInfo->nMinHeight)
nHeight = pStatusInfo->nMinHeight;
nHeight += 2*pStatusInfo->nBorderY;
NewSize(hWnd, nHeight, GetWindowLong(hWnd, GWL_STYLE),
rc.left, rc.top, rc.right, rc.bottom);
break;
}
case WM_PAINT:
if (!pStatusInfo)
break;
if ((pStatusInfo->sSimple.uType&SBT_NOSIMPLE) == SBT_NOSIMPLE)
PaintStatusWnd(hWnd, pStatusInfo, pStatusInfo->sInfo,
pStatusInfo->nParts, pStatusInfo->nBorderX, FALSE);
else
PaintStatusWnd(hWnd, pStatusInfo, &pStatusInfo->sSimple, 1, 1, FALSE);
return(0);
default:
break;
}
return DefWindowProc(hWnd, uMessage, wParam, lParam);
}
BOOL
InitStatusClass(HINSTANCE hInstance)
{
WNDCLASS rClass;
if (GetClassInfo(hInstance, szStatusClassW, &rClass))
return(TRUE);
rClass.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
rClass.lpfnWndProc = (WNDPROC)StatusWndProc;
rClass.cbClsExtra = 0;
rClass.cbWndExtra = sizeof(PSTATUSINFO);
rClass.hInstance = hInstance;
rClass.hIcon = NULL;
rClass.hCursor = LoadCursor(NULL, IDC_ARROW);
rClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
rClass.lpszMenuName = NULL;
rClass.lpszClassName = szStatusClassW;
return(RegisterClass(&rClass));
}
HWND WINAPI CreateStatusWindowA(LONG style, LPCSTR lpszText,
HWND hwndParent, WORD wID)
{
// Create a default window and return
return(CreateWindowA (szStatusClassA, lpszText, style,
-100, -100, 10, 10, hwndParent, (HMENU)wID, hInst, NULL));
}
HWND WINAPI CreateStatusWindowW(LONG style, LPCWSTR lpszText,
HWND hwndParent, WORD wID)
{
// Create a default window and return
return(CreateWindowW (szStatusClassW, lpszText, style,
-100, -100, 10, 10, hwndParent, (HMENU)wID, hInst, NULL));
}