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.
 
 
 
 
 
 

819 lines
22 KiB

#include "ctlspriv.h"
#define CURSORSLOP 3
static WCHAR szHeaderClassW[] = HEADERCLASSNAMEW;
static CCHAR szHeaderClassA[] = HEADERCLASSNAMEA;
static HCURSOR hSplit;
/* I only need one of these since you can only have capture on one window
* at a time
*/
static struct
{
HWND hWnd;
HWND hOldWnd;
HWND hwndParent;
UINT ID;
int nPart;
int nLastVisible;
int *pSaveParts;
RECT rc;
} state = { NULL, NULL, NULL, 0, -1, 0, NULL, { 0, 0, 0, 0 } } ;
Static void NEAR PASCAL BeginAdjust(HWND hWnd, PSTATUSINFO pStatusInfo, int nPart, POINT pt);
/* Return the partition index if the position is close enough; -1 otherwise
*/
Static int NEAR PASCAL
GetPart(PSTATUSINFO pStatusInfo, PSTRINGINFO pStringInfo, POINT pt)
{
int nParts;
for (nParts = 0; nParts < pStatusInfo->nParts - 1; ++nParts, ++pStringInfo)
{
if (pStringInfo->right - pt.x < CURSORSLOP && pStringInfo->right - pt.x > (1 - CURSORSLOP))
break;
if (nParts >= pStatusInfo->nParts - 2)
{
nParts = -1;
break;
}
}
return(nParts);
}
Static int NEAR PASCAL GetPrevVisible(PSTATUSINFO pStatusInfo, int nPart)
{
for (--nPart; nPart >= 0; --nPart)
if (pStatusInfo->sInfo[nPart].right > 0)
break;
return(nPart);
}
Static int NEAR PASCAL GetNextVisible(PSTATUSINFO pStatusInfo, int nPart)
{
for (++nPart; nPart < pStatusInfo->nParts; ++nPart)
if (pStatusInfo->sInfo[nPart].right > 0)
return(nPart);
return(-1);
}
/* Note that the handle returned here should NOT be freed by the caller
*/
Static HLOCAL NEAR PASCAL GetHeaderParts(HWND hWnd, PSTATUSINFO pStatusInfo, BOOL bAdjustLast)
{
static HLOCAL hSaveParts = NULL;
static int nSaveParts = 0;
HLOCAL hTemp;
PSTRINGINFO pSaveParts, pStringInfo, pNewInfo;
int nParts, nSprings, nTotal, nTemp, nLast, nLastVisible;
RECT rcClient;
/* Allocate a single moveable buffer that is large enough to hold the
* largest array of parts.
*/
nParts = pStatusInfo->nParts;
if (nParts > nSaveParts)
{
if (hSaveParts)
{
hTemp = LocalReAlloc(hSaveParts, nParts * sizeof(STRINGINFO), LMEM_MOVEABLE);
if (!hTemp)
return(NULL);
}
else
{
hTemp = LocalAlloc(LMEM_FIXED, nParts * sizeof(STRINGINFO));
if (!hTemp)
return(NULL);
}
hSaveParts = hTemp;
nSaveParts = nParts;
}
pSaveParts = (PSTRINGINFO) hSaveParts;
/* Go through the list, counting the number of "springs" and the
* minimum width.
*/
for (nTotal = 0, nSprings = 0, pNewInfo = pSaveParts, pStringInfo = pStatusInfo->sInfo;
nParts > 0; --nParts, ++pNewInfo, ++pStringInfo)
{
pNewInfo->pString = pStringInfo->pString;
pNewInfo->uType = pStringInfo->uType | SBT_NOBORDERS;
nTemp = pStringInfo->right;
if (nTemp < 0)
{
nTemp = 0;
pNewInfo->uType &= ~HBT_SPRING;
}
if (pNewInfo->uType & HBT_SPRING)
++nSprings;
nTotal += nTemp;
pNewInfo->right = nTemp;
}
/* Determine the amount left to distribute to the springs, and then
* distribute this amount evenly.
*/
GetClientRect(hWnd, &rcClient);
nTotal = rcClient.right - nTotal;
if (nTotal < 0)
nTotal = 0;
for (nParts = 0, nLast = 0, nLastVisible = -1, pNewInfo = pSaveParts,
pStringInfo = pStatusInfo->sInfo; nParts < pStatusInfo->nParts;
++nParts, ++pNewInfo, ++pStringInfo)
{
if ((pNewInfo->uType&HBT_SPRING) && nSprings)
{
nTemp = nTotal / nSprings;
--nSprings;
nTotal -= nTemp;
pNewInfo->right += nTemp;
}
/* Save the rightmost visible guy.
*/
if (pNewInfo->right)
nLastVisible = nParts;
/* Transform the width to an absolute position.
*/
pNewInfo->right += nLast;
nLast = pNewInfo->right;
}
if (bAdjustLast && nLastVisible>=0)
{
for (pNewInfo = pSaveParts + nLastVisible; nLastVisible < pStatusInfo->nParts;
++nLastVisible, ++pNewInfo)
pNewInfo->right = rcClient.right;
}
return(hSaveParts);
}
Static void NEAR PASCAL AdjustBorders(HWND hWnd, PSTATUSINFO pStatusInfo)
{
POINT pt, ptTemp, ptSave;
int nPart;
int accel = 0;
HWND hwndParent;
UINT uiID;
MSG msg;
RECT rc;
int nStart;
int nDirection;
HLOCAL hSaveParts;
PSTRINGINFO pSaveParts;
GetCursorPos(&ptSave);
GetClientRect(hWnd, &rc);
hwndParent = GetParent(hWnd);
uiID = GetWindowLong(hWnd, GWL_ID);
ShowCursor(TRUE);
pt.x = 0;
pt.y = (pStatusInfo->nFontHeight+1) / 2;
ClientToScreen(hWnd, &pt);
nDirection = 1;
nPart = pStatusInfo->nParts - 2;
goto MoveTheCursor;
for ( ; ; )
{
while (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE|PM_NOYIELD))
;
switch (msg.message)
{
case WM_KEYDOWN:
switch (msg.wParam)
{
case VK_TAB:
DoTab:
/* If the sift key is down, go backwards
*/
if (GetKeyState(VK_SHIFT) & 0x8000)
nDirection = -1;
else
nDirection = 1;
MoveTheCursor:
/* Make sure the previous adjust is cleaned up,
* then tell the app we are starting.
*/
if (state.nPart >= 0)
SendMessage(hWnd, WM_LBUTTONUP, 0, 0L);
SendMessage (hwndParent, WM_COMMAND,
GET_WM_COMMAND_MPS(uiID,0, HBN_BEGINADJUST));
hSaveParts = GetHeaderParts(hWnd, pStatusInfo, FALSE);
if (!hSaveParts)
goto EndAdjust;
pSaveParts = (PSTRINGINFO) hSaveParts;
/* Don't try to adjust anything that is not
* currently on the screen or has no visible
* cols to its right.
*/
nStart = nPart;
do {
nPart += nDirection;
if (nPart >= pStatusInfo->nParts - 1)
nPart = 0;
if (nPart < 0)
nPart = pStatusInfo->nParts-2;
if (nPart == nStart)
goto EndAdjust;
} while ((UINT)pSaveParts[nPart].right >= (UINT)rc.right
|| pStatusInfo->sInfo[nPart].right < 0
|| GetNextVisible(pStatusInfo, nPart) < 0);
/* Immediately go into adjusting mode; send BEGINADJUST right
* afterwards to get the right MenuHelp
*/
BeginAdjust(hWnd, pStatusInfo, nPart, pt);
SendMessage (hwndParent, WM_COMMAND,
GET_WM_COMMAND_MPS(uiID,state.nPart, HBN_BEGINADJUST));
break;
case VK_LEFT:
case VK_RIGHT:
case VK_UP:
case VK_DOWN:
GetCursorPos(&ptTemp);
++accel;
if (msg.wParam == VK_LEFT || msg.wParam == VK_UP)
ptTemp.x -= accel;
else
ptTemp.x += accel;
SetCursorPos(ptTemp.x, ptTemp.y);
break;
case VK_RETURN:
DoReturn:
SendMessage(hWnd, WM_LBUTTONUP, 0, 0L);
goto EndAdjust;
case VK_ESCAPE:
SendMessage(hWnd, WM_CHAR, VK_ESCAPE, 0L);
goto EndAdjust;
default:
break;
}
break;
case WM_KEYUP:
accel = 0;
break;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
goto DoReturn;
case WM_RBUTTONDOWN:
goto DoTab;
default:
TranslateMessage(&msg);
DispatchMessage(&msg);
break;
}
}
EndAdjust:
ShowCursor(FALSE);
SetCursorPos(ptSave.x, ptSave.y);
SendMessage (hwndParent, WM_COMMAND,
GET_WM_COMMAND_MPS(uiID, 0, HBN_ENDADJUST));
}
Static void NEAR PASCAL PaintHeaderWnd(HWND hWnd, PSTATUSINFO pStatusInfo)
{
HLOCAL hSaveParts;
PSTRINGINFO pStringInfo, pSaveParts;
int nParts, nBorderY; // andrewbe
int nBorderWidth, nBorderHeight; // andrewbe
HDC hDC;
HBRUSH hBrush, hOldBrush;
RECT rcClient;
hSaveParts = GetHeaderParts(hWnd, pStatusInfo, TRUE);
if (!hSaveParts)
return;
pSaveParts = (PSTRINGINFO) hSaveParts;
/* Let the status bar code draw the text
*/
PaintStatusWnd (hWnd, pStatusInfo, pSaveParts, pStatusInfo->nParts,
pStatusInfo->nBorderX, TRUE);
/* Now draw the lines between panes
*/
hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOWFRAME));
if (hBrush)
{
hDC = GetDC(hWnd);
hOldBrush = SelectObject(hDC, hBrush);
if (hOldBrush)
{
GetClientRect(hWnd, &rcClient);
nBorderWidth = pStatusInfo->nBorderPart; // andrewbe
nBorderY = 0; //
nBorderHeight = rcClient.bottom; // To stop the
// blasted
if (!(GetWindowLong(hWnd, GWL_STYLE)&CCS_NOHILITE)) { // flickering
nBorderY++; // (andrewbe)
nBorderHeight--; //
} //
for (nParts = pStatusInfo->nParts - 1, pStringInfo = pSaveParts;
nParts > 0; --nParts, ++pStringInfo)
{
PatBlt (hDC, pStringInfo->right, nBorderY, nBorderWidth, nBorderHeight,
PATCOPY);
}
SelectObject(hDC, hOldBrush);
}
ReleaseDC(hWnd, hDC);
DeleteObject(hBrush);
}
}
Static void NEAR PASCAL BeginAdjust(HWND hWnd, PSTATUSINFO pStatusInfo, int nPart, POINT pt)
{
HLOCAL hSaveParts;
PSTRINGINFO pSaveParts;
RECT rc;
int nParts;
/* Just make sure we are cleaned up from the last SetCapture
*/
if (state.nPart >= 0)
SendMessage(state.hWnd, WM_LBUTTONUP, 0, 0L);
hSaveParts = GetHeaderParts(hWnd, pStatusInfo, FALSE);
if (!hSaveParts)
return;
if (nPart >= 0)
state.nPart = nPart;
else
{
state.nPart = GetPart(pStatusInfo, hSaveParts, pt);
if (state.nPart < 0)
return;
}
/* Save the current state in case the user aborts
*/
state.pSaveParts = (int *)LocalAlloc(LMEM_FIXED,
pStatusInfo->nParts * sizeof(int));
if (!state.pSaveParts)
{
state.nPart = -1;
return;
}
for (nParts = pStatusInfo->nParts - 1; nParts >= 0; --nParts)
state.pSaveParts[nParts] = pStatusInfo->sInfo[nParts].right;
/* Set all min widths to their current widths. Special case nParts=0.
*/
pSaveParts = (PSTRINGINFO)hSaveParts;
for (nParts = pStatusInfo->nParts - 1, state.nLastVisible =- 1; nParts > 0; --nParts)
{
if (state.pSaveParts[nParts] > 0)
{
pStatusInfo->sInfo[nParts].right = pSaveParts[nParts].right
- pSaveParts[nParts-1].right;
if (state.nLastVisible < 0)
state.nLastVisible = nParts;
}
}
/* Set the last visible one very wide so there is never any spring.
*/
if (state.nLastVisible >= 0)
pStatusInfo->sInfo[state.nLastVisible].right = 0x3fff;
if (nParts == 0 && state.pSaveParts[0]> 0 )
pStatusInfo->sInfo[0].right = pSaveParts[0].right;
state.hWnd = hWnd;
pt.x = pSaveParts[state.nPart].right;
ClientToScreen(hWnd, &pt);
SetCursorPos(pt.x, pt.y);
SetCapture(hWnd);
state.hOldWnd = SetFocus(hWnd);
GetClientRect(hWnd, &state.rc);
if (state.nPart > 0)
state.rc.left = pSaveParts[state.nPart-1].right;
/* Clip the cursor to the appropriate area.
*/
rc = state.rc;
++rc.left;
/* Some code below assumes that state.rc.right is the width of the
* window.
*/
rc.right -= rc.left;
ClientToScreen(hWnd, (LPPOINT)&rc);
rc.right += rc.left;
rc.top = 0;
rc.bottom = GetSystemMetrics(SM_CYSCREEN);
ClipCursor(&rc);
SendMessage (hWnd, WM_SETCURSOR, (WPARAM)hWnd,
MAKELONG(HTCLIENT, WM_LBUTTONDOWN));
state.ID = GetWindowLong(hWnd, GWL_ID);
state.hwndParent = GetParent(hWnd);
SendMessage (state.hwndParent, WM_COMMAND,
GET_WM_COMMAND_MPS(state.ID,state.nPart, HBN_BEGINDRAG));
}
Static void NEAR PASCAL TermAdjust(void)
{
if (state.nPart < 0)
return;
state.nPart = -1;
LocalFree((HLOCAL)state.pSaveParts);
ReleaseCapture();
if (state.hOldWnd)
SetFocus(state.hOldWnd);
ClipCursor(NULL);
/* Send a dragging message just in case
*/
SendMessage(state.hwndParent, WM_COMMAND,
GET_WM_COMMAND_MPS(state.ID,state.nPart, HBN_DRAGGING));
SendMessage(state.hwndParent, WM_COMMAND,
GET_WM_COMMAND_MPS(state.ID,state.nPart, HBN_ENDDRAG));
}
Static void NEAR PASCAL AbortAdjust(PSTATUSINFO pStatusInfo)
{
int nPart;
if (state.nPart < 0)
return;
for (nPart = pStatusInfo->nParts - 1; nPart >= 0; --nPart)
pStatusInfo->sInfo[nPart].right = state.pSaveParts[nPart];
InvalidateRect(state.hWnd, NULL, TRUE);
TermAdjust();
}
/* Since a header bar and a status bar are so similar, I am just going to
* code the differences here, and call StatusWndProc for any messages I
* don't want to handle
*/
LRESULT CALLBACK HeaderWndProc(HWND hWnd, UINT uMessage, WPARAM wParam,
LPARAM lParam)
{
PSTATUSINFO pStatusInfo;
pStatusInfo = (PSTATUSINFO)GetWindowLong(hWnd, GWL_PSTATUSINFO);
if (!pStatusInfo)
{
if (uMessage == WM_CREATE)
{
#define lpcs ((LPCREATESTRUCT)lParam)
if (!(lpcs->style&(CCS_TOP|CCS_NOMOVEY|CCS_BOTTOM)))
{
lpcs->style |= CCS_NOMOVEY;
SetWindowLong(hWnd, GWL_STYLE, lpcs->style);
}
}
goto DoDefault;
}
switch (uMessage)
{
/* We just use the system font for DBCS systems
*/
#ifndef DBCS
case WM_SETFONT:
if (wParam == 0)
{
HDC hDC;
hDC = GetDC(hWnd);
wParam = (WPARAM)
#if 0
//
// Use unicode font
//
CreateFont(-8 * 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, UNICODE_FONT_NAME);
#endif
CreateFont(-8 * 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, szSansSerif);
ReleaseDC(hWnd, hDC);
if (!wParam)
break;
StatusWndProc(hWnd, uMessage, wParam, lParam);
pStatusInfo->bDefFont = TRUE;
return(TRUE);
}
break;
#endif
case WM_PAINT:
PaintHeaderWnd(hWnd, pStatusInfo);
return(TRUE);
case SB_SETBORDERS:
{
int nBorder;
LPINT lpInt;
lpInt = (LPINT)lParam;
nBorder = *lpInt++;
pStatusInfo->nBorderX = nBorder<0 ? 0 : nBorder;
nBorder = *lpInt++;
pStatusInfo->nBorderY = nBorder<0 ? 0 : nBorder;
nBorder = *lpInt;
pStatusInfo->nBorderPart = nBorder<0 ? GetSystemMetrics(SM_CXBORDER) // andrewbe
: nBorder;
return(TRUE);
}
case HB_SAVERESTORE:
{
int *pInt;
BOOL bRet;
LPTSTR *lpNames;
pInt = (int *)LocalAlloc(LMEM_FIXED, pStatusInfo->nParts * sizeof(int));
if (!pInt)
return(FALSE);
lpNames = (LPTSTR *)lParam;
if (wParam)
{
SendMessage (hWnd, SB_GETPARTS, pStatusInfo->nParts,
(LPARAM)(LPINT)pInt);
bRet = WritePrivateProfileStruct(lpNames[0], szHeaderClassW,
(LPBYTE)pInt, pStatusInfo->nParts*sizeof(int), lpNames[1]);
}
else
{
bRet = GetPrivateProfileStruct(lpNames[0], szHeaderClassW,
(LPBYTE)pInt, pStatusInfo->nParts*sizeof(int), lpNames[1]);
if (bRet)
SendMessage (hWnd, SB_SETPARTS, pStatusInfo->nParts,
(LPARAM)(LPINT)pInt);
}
LocalFree((HLOCAL)pInt);
return(bRet);
}
case HB_ADJUST:
AdjustBorders(hWnd, pStatusInfo);
break;
case HB_GETPARTS:
{
HLOCAL hSaveParts;
PSTRINGINFO pSaveParts;
LPINT lpResult;
hSaveParts = GetHeaderParts(hWnd, pStatusInfo, FALSE);
if (!hSaveParts)
return(0L);
pSaveParts = (PSTRINGINFO) hSaveParts;
if (wParam > (WPARAM)pStatusInfo->nParts)
wParam = pStatusInfo->nParts;
for (lpResult = (LPINT)lParam; wParam > 0; --wParam, ++lpResult, ++pSaveParts)
*lpResult = pSaveParts->right;
return((LRESULT)pStatusInfo->nParts);
}
case HB_SHOWTOGGLE:
if (wParam >= (WPARAM)pStatusInfo->nParts)
return(FALSE);
pStatusInfo->sInfo[wParam].right = -pStatusInfo->sInfo[wParam].right;
InvalidateRect(hWnd, NULL, TRUE);
return(TRUE);
case WM_SETCURSOR:
if ((HWND)wParam == hWnd)
{
POINT pt;
HLOCAL hSaveParts;
if (state.nPart >= 0)
{
SetCursor(hSplit);
return(TRUE);
}
else
{
GetCursorPos(&pt);
ScreenToClient(hWnd, &pt);
hSaveParts = GetHeaderParts(hWnd, pStatusInfo, FALSE);
if (!hSaveParts)
return(FALSE);
if (GetPart(pStatusInfo, hSaveParts, pt) >= 0)
{
SetCursor(hSplit);
return(TRUE);
}
}
}
break;
case WM_LBUTTONDOWN:
{
POINT pt;
LONG2POINT( lParam,pt );
BeginAdjust(hWnd, pStatusInfo, -1, pt);
break;
}
case WM_CHAR:
if (wParam == VK_ESCAPE)
AbortAdjust(pStatusInfo);
break;
case WM_MOUSEMOVE:
if (state.nPart>=0 && hWnd==state.hWnd)
{
/* We need to get the current position in case old MOUSEMOVE
* messages haven't been cleared yet.
*/
// andrewbe -- Fixed attempt to squeeze 64 bits into lParam
{
POINT CursorPos;
GetCursorPos(&CursorPos);
ScreenToClient(hWnd, &CursorPos);
lParam = MAKELPARAM((WORD)CursorPos.x, (WORD)CursorPos.y);
}
pStatusInfo->sInfo[state.nPart].right = LOWORD(lParam) - state.rc.left;
InvalidateRect(hWnd, &state.rc, FALSE);
UpdateWindow(hWnd);
SendMessage (state.hwndParent, WM_COMMAND,
GET_WM_COMMAND_MPS(state.ID,state.nPart, HBN_DRAGGING));
}
break;
case WM_LBUTTONUP:
if (state.nPart >= 0 && hWnd == state.hWnd) // fix access violation (andrewbe)
{
HLOCAL hSaveParts;
PSTRINGINFO pSaveParts;
/* Save the width of the last column if it is visible.
*/
if (state.nLastVisible >= 0)
{
hSaveParts = GetHeaderParts(hWnd, pStatusInfo, FALSE);
if (hSaveParts)
{
pSaveParts = (PSTRINGINFO) hSaveParts;
if (pSaveParts[state.nLastVisible-1].right < state.rc.right)
{
pStatusInfo->sInfo[state.nLastVisible].right =
state.rc.right - pSaveParts[state.nLastVisible-1].right;
}
else
{
pStatusInfo->sInfo[state.nLastVisible].right =
state.pSaveParts[state.nLastVisible];
}
}
}
TermAdjust();
break;
}
default:
break;
}
DoDefault:
return(StatusWndProc(hWnd, uMessage, wParam, lParam));
}
BOOL FAR PASCAL InitHeaderClass(HINSTANCE hInstance)
{
WNDCLASS rClass;
if (GetClassInfo(hInstance, szHeaderClassW, &rClass))
return(TRUE);
hSplit = LoadCursor(hInst, (LPTSTR) MAKEINTRESOURCE(IDC_SPLIT));
rClass.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
rClass.lpfnWndProc = (WNDPROC)HeaderWndProc;
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 = szHeaderClassW;
return(RegisterClass(&rClass));
}
HWND WINAPI CreateHeaderWindowA(LONG style, LPCSTR lpszText,
HWND hwndParent, WORD wID)
{
/* Create a default window and return
*/
return(CreateWindowA (szHeaderClassA, lpszText, style,
-100, -100, 10, 10, hwndParent, (HMENU)wID, hInst, NULL));
}
HWND WINAPI CreateHeaderWindowW(LONG style, LPCWSTR lpszText,
HWND hwndParent, WORD wID)
{
/* Create a default window and return
*/
return(CreateWindowW (szHeaderClassW, lpszText, style,
-100, -100, 10, 10, hwndParent, (HMENU)wID, hInst, NULL));
}