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.
 
 
 
 
 
 

1204 lines
34 KiB

/****************************************************************************\
*
* STATIC.C
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* Static Dialog Controls Routines
*
* 13-Nov-1990 mikeke from win3
* 29-Jan-1991 IanJa StaticPaint -> xxxStaticPaint; partial revalidation
* 01-Nov-1994 ChrisWil merged in Daytona/Chicago w/Ani-Icons.
*
\****************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* Local Routines.
*/
VOID xxxNextAniIconStep(PSTAT);
HANDLE xxxSetStaticImage(PSTAT,HANDLE,BOOL);
VOID xxxStaticLoadImage(PSTAT,LPWSTR);
/*
* Type table; this is used for validation of the image types.
*/
#define IMAGE_STMMAX IMAGE_ENHMETAFILE+1
static BYTE rgbType[IMAGE_STMMAX] = {
SS_BITMAP, // IMAGE_BITMAP
SS_ICON, // IMAGE_CURSOR
SS_ICON, // IMAGE_ICON
SS_ENHMETAFILE // IMAGE_ENHMETAFILE
};
/*
* LOBYTE of SS_ style is index into this array
*/
#define STK_OWNER 0x00
#define STK_IMAGE 0x01
#define STK_TEXT 0x02
#define STK_GRAPHIC 0x03
#define STK_TYPE 0x03
#define STK_ERASE 0x04
#define STK_USEFONT 0x08
#define STK_USETEXT 0x10
BYTE rgstk[] = {
STK_TEXT | STK_ERASE | STK_USEFONT | STK_USETEXT, // SS_LEFT
STK_TEXT | STK_ERASE | STK_USEFONT | STK_USETEXT, // SS_CENTER
STK_TEXT | STK_ERASE | STK_USEFONT | STK_USETEXT, // SS_RIGHT
STK_IMAGE, // SS_ICON
STK_GRAPHIC, // SS_BLACKRECT
STK_GRAPHIC, // SS_GRAYRECT
STK_GRAPHIC, // SS_WHITERECT
STK_GRAPHIC, // SS_BLACKFRAME
STK_GRAPHIC, // SS_GRAYFRAME
STK_GRAPHIC, // SS_WHITEFRAME
STK_OWNER, // SS_USERITEM
STK_TEXT | STK_USEFONT | STK_USETEXT, // SS_SIMPLE
STK_TEXT | STK_ERASE | STK_USEFONT | STK_USETEXT, // SS_LEFTNOWORDWRAP
STK_OWNER | STK_USEFONT | STK_USETEXT, // SS_OWNERDRAW
STK_IMAGE, // SS_BITMAP
STK_IMAGE | STK_ERASE, // SS_ENHMETAFILE
STK_GRAPHIC, // SS_ETCHEDHORZ
STK_GRAPHIC, // SS_ETCHEDVERT
STK_GRAPHIC // SS_ETCHEDFRAME
};
LOOKASIDE StaticLookaside;
/*
* Common macros for image handling.
*/
#define IsValidImage(imageType, realType, max) \
((imageType < max) && (rgbType[imageType] == realType))
/***************************************************************************\
* xxxSetStaticImage
*
* Sets bitmap/icon of static guy, either in response to a STM_SETxxxx
* message, or at create time.
\***************************************************************************/
HANDLE xxxSetStaticImage(
PSTAT pstat,
HANDLE hImage,
BOOL fDeleteIt)
{
UINT bType;
RECT rc;
RECT rcWindow;
HANDLE hImageOld;
DWORD dwRate;
UINT cicur;
BOOL fAnimated = FALSE;
PWND pwnd = pstat->spwnd;
HWND hwnd = HWq(pwnd);
CheckLock(pwnd);
bType = TestWF(pwnd, SFTYPEMASK);
/*
* If this is an old-ani-icon, then delete its timer.
*/
if (bType == SS_ICON && pstat->cicur > 1) {
/*
* Old cursor was an animated cursor, so kill the timer that is used
* to animate it.
*/
NtUserKillTimer(hwnd, IDSYS_STANIMATE);
}
/*
* Initialize the old-image return value.
*/
hImageOld = pstat->hImage;
rc.right = rc.bottom = 0;
if (hImage != NULL) {
switch (bType) {
case SS_ENHMETAFILE: {
/*
* We do NOT resize the window.
*/
rc.right = pwnd->rcClient.right - pwnd->rcClient.left;
rc.bottom = pwnd->rcClient.bottom - pwnd->rcClient.top;
break;
}
case SS_BITMAP: {
BITMAP bmp;
if (GetObject(hImage, sizeof(BITMAP), &bmp)) {
rc.right = bmp.bmWidth;
rc.bottom = bmp.bmHeight;
}
}
break;
case SS_ICON: {
NtUserGetIconSize(hImage, 0, &rc.right, &rc.bottom);
rc.bottom /= 2;
pstat->cicur = 0;
pstat->iicur = 0;
if (GetCursorFrameInfo(hImage, NULL, 0, &dwRate, &cicur)) {
fAnimated = (cicur > 1);
pstat->cicur = cicur;
}
}
break;
}
}
pstat->hImage = hImage;
pstat->fDeleteIt = fDeleteIt;
/*
* Resize static to fit. Do NOT do this for SS_CENTERIMAGE or
* SS_REALSIZECONTROL.
*/
if (!TestWF(pwnd, SFCENTERIMAGE) && !TestWF(pwnd, SFREALSIZECONTROL)) {
/*
* Get current window rect in parent's client coordinates.
*/
GetRect(pwnd, &rcWindow, GRECT_WINDOW | GRECT_PARENTCOORDS);
/*
* Get new window dimensions.
*/
rc.left = 0;
rc.top = 0;
if (rc.right && rc.bottom) {
_AdjustWindowRectEx(&rc, pwnd->style, FALSE, pwnd->ExStyle);
rc.right -= rc.left;
rc.bottom -= rc.top;
}
NtUserSetWindowPos(hwnd,
HWND_TOP,
0,
0,
rc.right,
rc.bottom,
SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
}
if (TestWF(pwnd, WFVISIBLE)) {
NtUserInvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
/*
* If this is an aimated-icon, then start the timer for the animation
* sequence.
*/
if(fAnimated) {
GetCursorFrameInfo(pstat->hImage, NULL, pstat->iicur, &dwRate, &cicur);
dwRate = max(200, dwRate * 100 / 6);
NtUserSetTimer(hwnd, IDSYS_STANIMATE, dwRate, NULL);
}
return hImageOld;
}
/***************************************************************************\
* StaticLoadImage
*
* Loads the icon or bitmap from the app's resource file if a name was
* specified in the dialog template. We assume that the name is the name of
* the resource to load.
\***************************************************************************/
VOID xxxStaticLoadImage(
PSTAT pstat,
LPWSTR lpszName)
{
HANDLE hImage = NULL;
PWND pwnd = pstat->spwnd;
CheckLock(pwnd);
if (lpszName && *lpszName) {
/*
* Only try to load the icon/bitmap if the string is non null.
*/
if (*(BYTE FAR *)lpszName == 0xFF)
lpszName = MAKEINTRESOURCE(((LPWORD)lpszName)[1]);
/*
* Load the image. If it can't be found in the app, try the
* display driver.
*/
if (lpszName) {
switch (TestWF(pwnd, SFTYPEMASK)) {
case SS_BITMAP:
/*
* If the window is not owned by the server, first call
* back out to the client.
*/
if (!gfServerProcess && pwnd->hModule) {
hImage = LoadBitmap(KHANDLE_TO_HANDLE(pwnd->hModule), lpszName);
}
/*
* If the above didn't load it, try loading it from the
* display driver (hmod == NULL).
*/
if (hImage == NULL) {
hImage = LoadBitmap(NULL, lpszName);
}
break;
case SS_ICON:
if (TestWF(pwnd, SFREALSIZEIMAGE)) {
if (!gfServerProcess && pwnd->hModule) {
hImage = LoadImage(KHANDLE_TO_HANDLE(pwnd->hModule), lpszName, IMAGE_ICON, 0, 0, 0);
}
} else {
/*
* If the window is not owned by the server, first call
* back out to the client. Try loading both icons/cursor
* types.
*/
if (!gfServerProcess && pwnd->hModule) {
hImage = LoadIcon(KHANDLE_TO_HANDLE(pwnd->hModule),
lpszName);
/*
* We will also try to load a cursor-format if the
* window is 4.0 compatible. Icons/Cursors are really
* the same. We don't do this for 3.x apps for the
* usual compatibility reasons.
*/
if (hImage == NULL && TestWF(pwnd, WFWIN40COMPAT)) {
hImage = LoadCursor(KHANDLE_TO_HANDLE(pwnd->hModule), lpszName);
}
}
/*
* If the above didn't load it, try loading it from the
* display driver (hmod == NULL).
*/
if (hImage == NULL) {
hImage = LoadIcon(NULL, lpszName);
}
}
break;
}
/*
* Set the image if it was loaded.
*/
if (hImage) {
xxxSetStaticImage(pstat, hImage, TRUE);
}
}
}
}
/***************************************************************************\
* StaticCallback
*
* Draws text statics, called by DrawState.
\***************************************************************************/
BOOL CALLBACK StaticCallback(
HDC hdc,
LPARAM lData,
WPARAM wData,
int cx,
int cy)
{
PWND pwnd = (PWND)lData;
UINT style;
LPWSTR lpszName;
RECT rc;
BYTE bType;
UNREFERENCED_PARAMETER(wData);
bType = TestWF(pwnd, SFTYPEMASK);
UserAssert(rgstk[bType] & STK_USETEXT);
if (pwnd->strName.Length) {
lpszName = REBASE(pwnd, strName.Buffer);
style = DT_NOCLIP | DT_EXPANDTABS;
if (bType != LOBYTE(SS_LEFTNOWORDWRAP)) {
style |= DT_WORDBREAK;
style |= (UINT)(bType - LOBYTE(SS_LEFT));
if (TestWF(pwnd, SFEDITCONTROL)) {
style |= DT_EDITCONTROL;
}
}
switch (TestWF(pwnd, SFELLIPSISMASK)) {
case HIBYTE(LOWORD(SS_ENDELLIPSIS)):
style |= DT_END_ELLIPSIS | DT_SINGLELINE;
break;
case HIBYTE(LOWORD(SS_PATHELLIPSIS)):
style |= DT_PATH_ELLIPSIS | DT_SINGLELINE;
break;
case HIBYTE(LOWORD(SS_WORDELLIPSIS)):
style |= DT_WORD_ELLIPSIS | DT_SINGLELINE;
break;
}
if (TestWF(pwnd, SFNOPREFIX)) {
style |= DT_NOPREFIX;
}
if (TestWF(pwnd, SFCENTERIMAGE)) {
style |= DT_VCENTER | DT_SINGLELINE;
}
rc.left = 0;
rc.top = 0;
rc.right = cx;
rc.bottom = cy;
if (TestWF(pwnd, WEFPUIACCELHIDDEN)) {
style |= DT_HIDEPREFIX;
} else if (((PSTATWND)pwnd)->pstat->fPaintKbdCuesOnly) {
style |= DT_PREFIXONLY;
}
DrawTextExW(hdc, lpszName, -1, &rc, (DWORD)style, NULL);
}
return TRUE;
}
/***************************************************************************\
* xxxStaticPaint
*
* History:
\***************************************************************************/
VOID xxxStaticPaint(
PSTAT pstat,
HDC hdc,
BOOL fClip)
{
PWND pwndParent;
RECT rc;
UINT cmd;
BYTE bType;
BOOL fFont;
HBRUSH hbrControl;
UINT oldAlign;
DWORD dwOldLayout = 0;
HANDLE hfontOld = NULL;
PWND pwnd = pstat->spwnd;
HWND hwnd = HWq(pwnd);
CheckLock(pwnd);
if (TestWF(pwnd, WEFRTLREADING)) {
oldAlign = GetTextAlign(hdc);
SetTextAlign(hdc, oldAlign | TA_RTLREADING);
}
bType = TestWF(pwnd, SFTYPEMASK);
_GetClientRect(pwnd, &rc);
if (fClip) {
IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
}
fFont = (rgstk[bType] & STK_USEFONT) && (pstat->hFont != NULL);
if (fFont) {
hfontOld = SelectObject(hdc, pstat->hFont);
}
/*
* Send WM_CTLCOLORSTATIC to all statics (even frames) for 1.03
* compatibility.
*/
SetBkMode(hdc, OPAQUE);
hbrControl = GetControlBrush(hwnd, hdc, WM_CTLCOLORSTATIC);
/*
* Do we erase the background? We don't for SS_OWNERDRAW
* and STK_GRAPHIC kind of things.
*/
pwndParent = REBASEPWND(pwnd, spwndParent);
if ((rgstk[bType] & STK_ERASE) && !pstat->fPaintKbdCuesOnly) {
PaintRect(HW(pwndParent), hwnd, hdc, hbrControl, &rc);
}
switch (LOBYTE(bType)) {
case SS_ICON:
if (pstat->hImage) {
int cx;
int cy;
POINT pt;
if (TestWF(pwnd,WEFLAYOUTRTL)) {
dwOldLayout = SetLayoutWidth(hdc, -1, 0);
}
/*
* Perform the correct rect-setup.
*/
if (TestWF(pwnd,SFCENTERIMAGE)) {
NtUserGetIconSize(pstat->hImage, pstat->iicur, &cx, &cy);
cy >>= 1;
rc.left = (rc.right - cx) / 2;
rc.right = (rc.left + cx);
rc.top = (rc.bottom - cy) / 2;
rc.bottom = (rc.top + cy);
} else {
cx = rc.right - rc.left;
cy = rc.bottom - rc.top;
}
/*
* Output the icon. If it's animated, we indicate
* the step-frame to output.
*/
if (GETFNID(pwndParent) == FNID_DESKTOP) {
SetBrushOrgEx(hdc, 0, 0, &pt);
} else {
SetBrushOrgEx(
hdc,
pwndParent->rcClient.left - pwnd->rcClient.left,
pwndParent->rcClient.top - pwnd->rcClient.top,
&pt);
}
DrawIconEx(hdc, rc.left, rc.top, pstat->hImage, cx, cy,
pstat->iicur, hbrControl, DI_NORMAL);
SetBrushOrgEx(hdc, pt.x, pt.y, NULL);
if (TestWF(pwnd,WEFLAYOUTRTL)) {
SetLayoutWidth(hdc, -1, dwOldLayout);
}
} else {
/*
* Empty! Need to erase.
*/
PaintRect(HW(pwndParent), hwnd, hdc, hbrControl, &rc);
}
break;
case SS_BITMAP:
if (pstat->hImage) {
BITMAP bmp;
HBITMAP hbmpT;
RECT rcTmp;
BOOL fErase;
/*
* Get the bitmap information. If this fails, then we
* can assume somethings wrong with its format...don't
* draw in this case.
*/
if (GetObject(pstat->hImage, sizeof(BITMAP), &bmp)) {
if (TestWF(pwnd, SFCENTERIMAGE)) {
fErase = ((bmp.bmWidth < rc.right) ||
(bmp.bmHeight < rc.bottom));
rc.left = (rc.right - bmp.bmWidth) >> 1;
rc.right = (rc.left + bmp.bmWidth);
rc.top = (rc.bottom - bmp.bmHeight) >> 1;
rc.bottom = (rc.top + bmp.bmHeight);
} else {
fErase = FALSE;
}
/*
* Select in the bitmap and blt it to the client-surface.
*/
RtlEnterCriticalSection(&gcsHdc);
hbmpT = SelectObject(ghdcBits2, pstat->hImage);
StretchBlt(hdc, rc.left, rc.top, rc.right-rc.left,
rc.bottom-rc.top, ghdcBits2, 0, 0, bmp.bmWidth,
bmp.bmHeight, SRCCOPY|NOMIRRORBITMAP);
/*
* Only need to erase the background if the image is
* centered and it's smaller than the client-area.
*/
if (fErase) {
HBRUSH hbr;
if (hbr = CreateSolidBrush(GetPixel(ghdcBits2, 0, 0))) {
POLYPATBLT PolyData;
ExcludeClipRect(hdc, rc.left, rc.top,
rc.right, rc.bottom);
_GetClientRect(pwnd, &rcTmp);
PolyData.x = 0;
PolyData.y = 0;
PolyData.cx = rcTmp.right;
PolyData.cy = rcTmp.bottom;
PolyData.BrClr.hbr = hbr;
PolyPatBlt(hdc,PATCOPY,&PolyData,1,PPB_BRUSH);
DeleteObject(hbr);
}
}
if (hbmpT) {
SelectObject(ghdcBits2, hbmpT);
}
RtlLeaveCriticalSection(&gcsHdc);
}
}
break;
case SS_ENHMETAFILE:
if (pstat->hImage) {
RECT rcl;
rcl.left = rc.left;
rcl.top = rc.top;
rcl.right = rc.right;
rcl.bottom = rc.bottom;
PlayEnhMetaFile(hdc, pstat->hImage, &rcl);
}
break;
case SS_OWNERDRAW: {
DRAWITEMSTRUCT dis;
dis.CtlType = ODT_STATIC;
dis.CtlID = PtrToUlong(pwnd->spmenu);
dis.itemAction = ODA_DRAWENTIRE;
dis.itemState = (TestWF(pwnd, WFDISABLED) ? ODS_DISABLED : 0);
dis.hwndItem = hwnd;
dis.hDC = hdc;
dis.itemData = 0L;
dis.rcItem = rc;
if (TestWF(pwnd, WEFPUIACCELHIDDEN)) {
dis.itemState |= ODS_NOACCEL;
}
/*
* Send a WM_DRAWITEM message to the parent.
*/
SendMessage(HW(pwndParent), WM_DRAWITEM, (WPARAM)dis.CtlID, (LPARAM)&dis);
}
break;
case SS_LEFT:
case SS_CENTER:
case SS_RIGHT:
case SS_LEFTNOWORDWRAP:
if (pwnd->strName.Length) {
UINT dstFlags;
dstFlags = DST_COMPLEX;
if (TestWF(pwnd, WFDISABLED)) {
dstFlags |= DSS_DISABLED;
}
DrawState(hdc,
SYSHBR(WINDOWTEXT),
StaticCallback,
(LPARAM)pwnd,
(WPARAM)TRUE,
rc.left,
rc.top,
rc.right - rc.left,
rc.bottom - rc.top,
dstFlags);
}
break;
case SS_SIMPLE: {
LPWSTR lpName;
UINT cchName;
/*
* The "Simple" bType assumes everything, including the following:
* 1. The Text exists and fits on one line.
* 2. The Static item is always enabled.
* 3. The Static item is never changed to be a shorter string.
* 4. The Parent never responds to the CTLCOLOR message
*/
if (pwnd->strName.Length) {
lpName = REBASE(pwnd, strName.Buffer);
cchName = pwnd->strName.Length / sizeof(WCHAR);
} else {
lpName = (LPWSTR)szNull;
cchName = 0;
}
if (TestWF(pwnd,SFNOPREFIX)) {
ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE | ETO_CLIPPED,
&rc, lpName, cchName, 0L);
} else {
/*
* Use OPAQUE for speed.
*/
DWORD dwFlags;
if (TestWF(pwnd, WEFPUIACCELHIDDEN)) {
dwFlags = DT_HIDEPREFIX;
} else if (pstat->fPaintKbdCuesOnly) {
dwFlags = DT_PREFIXONLY;
} else {
dwFlags = 0;
}
PSMTextOut(hdc, rc.left, rc.top,
lpName, cchName, dwFlags);
}
}
break;
case SS_BLACKFRAME:
cmd = (COLOR_3DDKSHADOW << 3);
goto StatFrame;
case SS_GRAYFRAME:
cmd = (COLOR_3DSHADOW << 3);
goto StatFrame;
case SS_WHITEFRAME:
cmd = (COLOR_3DHILIGHT << 3);
StatFrame:
DrawFrame(hdc, &rc, 1, cmd);
break;
case SS_BLACKRECT:
hbrControl = SYSHBR(3DDKSHADOW);
goto StatRect;
case SS_GRAYRECT:
hbrControl = SYSHBR(3DSHADOW);
goto StatRect;
case SS_WHITERECT:
hbrControl = SYSHBR(3DHILIGHT);
StatRect:
PaintRect(HW(pwndParent), hwnd, hdc, hbrControl, &rc);
break;
case SS_ETCHEDFRAME:
DrawEdge(hdc, &rc, EDGE_ETCHED, BF_RECT);
break;
}
if (hfontOld) {
SelectObject(hdc, hfontOld);
}
if (TestWF(pwnd, WEFRTLREADING)) {
SetTextAlign(hdc, oldAlign);
}
}
/***************************************************************************\
*
* StaticRepaint()
*
\***************************************************************************/
VOID StaticRepaint(
PSTAT pstat)
{
PWND pwnd = pstat->spwnd;
if (IsVisible(pwnd)) {
HDC hdc;
HWND hwnd = HWq(pwnd);
if (hdc = NtUserGetDC(hwnd)) {
xxxStaticPaint(pstat, hdc, TRUE);
NtUserReleaseDC(hwnd, hdc);
}
}
}
/***************************************************************************\
*
* StaticNotifyParent()
*
* Sends WM_COMMAND notification messages.
*
\***************************************************************************/
// LATER mikeke why do we have multiple versions of notifyparent?
LRESULT FAR PASCAL StaticNotifyParent(
PWND pwnd,
PWND pwndParent,
int nCode)
{
LRESULT lret;
TL tlpwndParent;
UserAssert(pwnd);
if (!pwndParent) {
pwndParent = REBASEPWND(pwnd, spwndParent);
}
ThreadLock(pwndParent, &tlpwndParent);
lret = SendMessage(HW(pwndParent), WM_COMMAND,
MAKELONG(PTR_TO_ID(pwnd->spmenu), nCode), (LPARAM)HWq(pwnd));
ThreadUnlock(&tlpwndParent);
return lret;
}
/***************************************************************************\
* StaticWndProc
*
* History:
\***************************************************************************/
LRESULT APIENTRY StaticWndProcWorker(
PWND pwnd,
UINT message,
WPARAM wParam,
LPARAM lParam,
DWORD fAnsi)
{
HWND hwnd = HWq(pwnd);
BYTE bType;
PSTAT pstat;
static BOOL fInit = TRUE;
CheckLock(pwnd);
VALIDATECLASSANDSIZE(pwnd, FNID_STATIC);
INITCONTROLLOOKASIDE(&StaticLookaside, STAT, spwnd, 8);
/*
* If the control is not interested in this message,
* pass it to DefWindowProc.
*/
if (!FWINDOWMSG(message, FNID_STATIC))
return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
/*
* Get the pstat for the given window now since we will use it a lot in
* various handlers. This was stored using SetWindowLong(hwnd,0,pstat) when
* we initially created the static control.
*/
pstat = ((PSTATWND)pwnd)->pstat;
/*
* Get the control's type
*/
bType = TestWF(pwnd, SFTYPEMASK);
switch (message) {
case STM_GETICON:
wParam = IMAGE_ICON;
case STM_GETIMAGE:
if (IsValidImage(wParam, bType, IMAGE_STMMAX)) {
return (LRESULT)pstat->hImage;
}
break;
case STM_SETICON:
lParam = (LPARAM)wParam;
wParam = IMAGE_ICON;
case STM_SETIMAGE:
if (IsValidImage(wParam, bType, IMAGE_STMMAX)) {
return (LRESULT)xxxSetStaticImage(pstat, (HANDLE)lParam, FALSE);
}
break;
case WM_ERASEBKGND:
/*
* The control will be erased in xxxStaticPaint().
*/
return TRUE;
case WM_PRINTCLIENT:
xxxStaticPaint(pstat, (HDC)wParam, FALSE);
break;
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
if ((hdc = (HDC)wParam) == NULL) {
hdc = NtUserBeginPaint(hwnd, &ps);
}
if (IsVisible(pwnd)) {
xxxStaticPaint(pstat, hdc, !wParam);
}
/*
* If hwnd was destroyed, BeginPaint was automatically undone.
*/
if (!wParam) {
NtUserEndPaint(hwnd, &ps);
}
}
break;
case WM_CREATE:
if ((rgstk[bType] & STK_TYPE) == STK_IMAGE) {
/*
* Pull the name from LPCREATESTRUCT like Win95 does
*/
LPWSTR lpszName;
LPSTR lpszAnsiName;
struct {
WORD tag;
BYTE ordLo;
BYTE ordHi;
} dwUnicodeOrdinal;
if (fAnsi) {
/*
* Convert the ANSI string to unicode if it exists.
*/
lpszAnsiName = (LPSTR)((LPCREATESTRUCT)lParam)->lpszName;
if (lpszAnsiName) {
if (lpszAnsiName[0] == (CHAR)0xff) {
/*
* Convert ANSI ordinal to UNICODE ordinal
*/
dwUnicodeOrdinal.tag = 0xFFFF;
dwUnicodeOrdinal.ordLo = lpszAnsiName[1];
dwUnicodeOrdinal.ordHi = lpszAnsiName[2];
lpszName = (LPWSTR)&dwUnicodeOrdinal;
} else {
MBToWCSEx(0, lpszAnsiName, -1, &lpszName, -1, TRUE);
}
} else {
lpszName = NULL;
}
} else {
lpszName = (LPWSTR)(((LPCREATESTRUCT)lParam)->lpszName);
}
/*
* Load the image
*/
xxxStaticLoadImage(pstat, lpszName);
if (fAnsi && lpszName && lpszName != (LPWSTR)&dwUnicodeOrdinal) {
/*
* Free the converted ANSI string.
*/
UserLocalFree(lpszName);
}
} else if (bType == SS_ETCHEDHORZ || bType == SS_ETCHEDVERT) {
/*
* Resize static window to fit edge. Horizontal dudes make
* bottom one edge from top, vertical dudes make right edge one
* edge from left.
*/
RECT rcClient;
_GetClientRect(pwnd, &rcClient);
if (bType == SS_ETCHEDHORZ) {
rcClient.bottom = SYSMET(CYEDGE);
} else {
rcClient.right = SYSMET(CXEDGE);
}
NtUserSetWindowPos(hwnd,
HWND_TOP,
0,
0,
rcClient.right,
rcClient.bottom,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
break;
case WM_DESTROY:
if (((rgstk[bType] & STK_TYPE) == STK_IMAGE) &&
(pstat->hImage != NULL) &&
(pstat->fDeleteIt)) {
if (bType == SS_BITMAP) {
DeleteObject(pstat->hImage);
} else if (bType == SS_ICON) {
if (pstat->cicur > 1) {
/*
* Kill the animated cursor timer
*/
NtUserKillTimer(hwnd, IDSYS_STANIMATE);
}
NtUserDestroyCursor((HCURSOR)(pstat->hImage), CURSOR_CALLFROMCLIENT);
}
}
break;
case WM_NCCREATE:
if (TestWF(pwnd,WEFRIGHT)) {
NtUserAlterWindowStyle(hwnd, SS_TYPEMASK, SS_RIGHT);
}
if (TestWF(pwnd, SFSUNKEN) ||
((bType == LOBYTE(SS_ETCHEDHORZ)) || (bType == LOBYTE(SS_ETCHEDVERT)))) {
SetWindowState(pwnd, WEFSTATICEDGE);
}
goto CallDWP;
case WM_NCDESTROY:
case WM_FINALDESTROY:
if (pstat) {
Unlock(&pstat->spwnd);
FreeLookasideEntry(&StaticLookaside, pstat);
}
NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT);
break;
case WM_NCHITTEST:
return (TestWF(pwnd, SFNOTIFY) ? HTCLIENT : HTTRANSPARENT);
case WM_LBUTTONDOWN:
case WM_NCLBUTTONDOWN:
if (TestWF(pwnd, SFNOTIFY)) {
/*
* It is acceptable for an app to destroy a static label
* in response to a STN_CLICKED notification.
*/
StaticNotifyParent(pwnd, NULL, STN_CLICKED);
}
break;
case WM_LBUTTONDBLCLK:
case WM_NCLBUTTONDBLCLK:
if (TestWF(pwnd, SFNOTIFY)) {
/*
* It is acceptable for an app to destroy a static label in
* response to a STN_DBLCLK notification.
*/
StaticNotifyParent(pwnd, NULL, STN_DBLCLK);
}
break;
case WM_SETTEXT:
/*
* No more hack to set icon/bitmap via WM_SETTEXT!
*/
if (rgstk[bType] & STK_USETEXT) {
if (_DefSetText(hwnd, (LPWSTR)lParam, fAnsi)) {
StaticRepaint(pstat);
return TRUE;
}
}
break;
case WM_ENABLE:
StaticRepaint(pstat);
if (TestWF(pwnd, SFNOTIFY)) {
StaticNotifyParent(pwnd, NULL, (wParam ? STN_ENABLE : STN_DISABLE));
}
break;
case WM_GETDLGCODE:
return (LONG)DLGC_STATIC;
case WM_SETFONT:
/*
* wParam - handle to the font
* lParam - if true, redraw else don't
*/
if (rgstk[bType] & STK_USEFONT) {
pstat->hFont = (HANDLE)wParam;
if (lParam && TestWF(pwnd, WFVISIBLE)) {
NtUserInvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
}
break;
case WM_GETFONT:
if (rgstk[bType] & STK_USEFONT) {
return (LRESULT)pstat->hFont;
}
break;
case WM_TIMER:
if (wParam == IDSYS_STANIMATE) {
xxxNextAniIconStep(pstat);
}
break;
/*
* case WM_GETTEXT:
* No more hack to get icon/bitmap via WM_GETTEXT!
*/
case WM_INPUTLANGCHANGEREQUEST:
if (IS_IME_ENABLED() || IS_MIDEAST_ENABLED()) {
/*
* #115190
* If the window is one of controls on top of dialogbox,
* let the parent dialog handle it.
*/
if (TestwndChild(pwnd) && pwnd->spwndParent) {
PWND pwndParent = REBASEALWAYS(pwnd, spwndParent);
if (pwndParent) {
PCLS pclsParent = REBASEALWAYS(pwndParent, pcls);
UserAssert(pclsParent != NULL);
if (pclsParent->atomClassName == gpsi->atomSysClass[ICLS_DIALOG]) {
return SendMessageWorker(pwndParent, message, wParam, lParam, FALSE);
}
}
}
}
goto CallDWP;
case WM_UPDATEUISTATE:
{
/*
* DWP will change the UIState bits accordingly
*/
DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
if (HIWORD(wParam) & UISF_HIDEACCEL) {
/*
* Change in AccelHidden state: need to repaint
*/
if (ISSSTEXTOROD(bType)) {
pstat->fPaintKbdCuesOnly = TRUE;
StaticRepaint(pstat);
pstat->fPaintKbdCuesOnly = FALSE;
}
}
}
break;
default:
CallDWP:
return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
}
return 0;
}
LRESULT WINAPI StaticWndProcA(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
PWND pwnd;
if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
return 0;
}
return StaticWndProcWorker(pwnd, message, wParam, lParam, TRUE);
}
LRESULT WINAPI StaticWndProcW(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
PWND pwnd;
if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
return 0;
}
return StaticWndProcWorker(pwnd, message, wParam, lParam, FALSE);
}
/***************************************************************************\
* Next Animated Icon Step
*
* Advances to the next step in an animaged icon.
\***************************************************************************/
VOID xxxNextAniIconStep(
PSTAT pstat)
{
DWORD dwRate;
PWND pwnd = pstat->spwnd;
HWND hwnd = HWq(pwnd);
/*
* Stop the timer for the next animation step.
*/
NtUserKillTimer(hwnd, IDSYS_STANIMATE);
if (++(pstat->iicur) >= pstat->cicur) {
pstat->iicur = 0;
}
GetCursorFrameInfo(pstat->hImage, NULL, pstat->iicur, &dwRate, &pstat->cicur);
dwRate = max(200, dwRate * 100 / 6);
NtUserInvalidateRect(hwnd, NULL, FALSE);
UpdateWindow(hwnd);
NtUserSetTimer(hwnd, IDSYS_STANIMATE, dwRate, NULL);
}