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

  1. /****************************************************************************\
  2. *
  3. * STATIC.C
  4. *
  5. * Copyright (c) 1985 - 1999, Microsoft Corporation
  6. *
  7. * Static Dialog Controls Routines
  8. *
  9. * 13-Nov-1990 mikeke from win3
  10. * 29-Jan-1991 IanJa StaticPaint -> xxxStaticPaint; partial revalidation
  11. * 01-Nov-1994 ChrisWil merged in Daytona/Chicago w/Ani-Icons.
  12. *
  13. \****************************************************************************/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. /*
  17. * Local Routines.
  18. */
  19. VOID xxxNextAniIconStep(PSTAT);
  20. HANDLE xxxSetStaticImage(PSTAT,HANDLE,BOOL);
  21. VOID xxxStaticLoadImage(PSTAT,LPWSTR);
  22. /*
  23. * Type table; this is used for validation of the image types.
  24. */
  25. #define IMAGE_STMMAX IMAGE_ENHMETAFILE+1
  26. static BYTE rgbType[IMAGE_STMMAX] = {
  27. SS_BITMAP, // IMAGE_BITMAP
  28. SS_ICON, // IMAGE_CURSOR
  29. SS_ICON, // IMAGE_ICON
  30. SS_ENHMETAFILE // IMAGE_ENHMETAFILE
  31. };
  32. /*
  33. * LOBYTE of SS_ style is index into this array
  34. */
  35. #define STK_OWNER 0x00
  36. #define STK_IMAGE 0x01
  37. #define STK_TEXT 0x02
  38. #define STK_GRAPHIC 0x03
  39. #define STK_TYPE 0x03
  40. #define STK_ERASE 0x04
  41. #define STK_USEFONT 0x08
  42. #define STK_USETEXT 0x10
  43. BYTE rgstk[] = {
  44. STK_TEXT | STK_ERASE | STK_USEFONT | STK_USETEXT, // SS_LEFT
  45. STK_TEXT | STK_ERASE | STK_USEFONT | STK_USETEXT, // SS_CENTER
  46. STK_TEXT | STK_ERASE | STK_USEFONT | STK_USETEXT, // SS_RIGHT
  47. STK_IMAGE, // SS_ICON
  48. STK_GRAPHIC, // SS_BLACKRECT
  49. STK_GRAPHIC, // SS_GRAYRECT
  50. STK_GRAPHIC, // SS_WHITERECT
  51. STK_GRAPHIC, // SS_BLACKFRAME
  52. STK_GRAPHIC, // SS_GRAYFRAME
  53. STK_GRAPHIC, // SS_WHITEFRAME
  54. STK_OWNER, // SS_USERITEM
  55. STK_TEXT | STK_USEFONT | STK_USETEXT, // SS_SIMPLE
  56. STK_TEXT | STK_ERASE | STK_USEFONT | STK_USETEXT, // SS_LEFTNOWORDWRAP
  57. STK_OWNER | STK_USEFONT | STK_USETEXT, // SS_OWNERDRAW
  58. STK_IMAGE, // SS_BITMAP
  59. STK_IMAGE | STK_ERASE, // SS_ENHMETAFILE
  60. STK_GRAPHIC, // SS_ETCHEDHORZ
  61. STK_GRAPHIC, // SS_ETCHEDVERT
  62. STK_GRAPHIC // SS_ETCHEDFRAME
  63. };
  64. LOOKASIDE StaticLookaside;
  65. /*
  66. * Common macros for image handling.
  67. */
  68. #define IsValidImage(imageType, realType, max) \
  69. ((imageType < max) && (rgbType[imageType] == realType))
  70. /***************************************************************************\
  71. * xxxSetStaticImage
  72. *
  73. * Sets bitmap/icon of static guy, either in response to a STM_SETxxxx
  74. * message, or at create time.
  75. \***************************************************************************/
  76. HANDLE xxxSetStaticImage(
  77. PSTAT pstat,
  78. HANDLE hImage,
  79. BOOL fDeleteIt)
  80. {
  81. UINT bType;
  82. RECT rc;
  83. RECT rcWindow;
  84. HANDLE hImageOld;
  85. DWORD dwRate;
  86. UINT cicur;
  87. BOOL fAnimated = FALSE;
  88. PWND pwnd = pstat->spwnd;
  89. HWND hwnd = HWq(pwnd);
  90. CheckLock(pwnd);
  91. bType = TestWF(pwnd, SFTYPEMASK);
  92. /*
  93. * If this is an old-ani-icon, then delete its timer.
  94. */
  95. if (bType == SS_ICON && pstat->cicur > 1) {
  96. /*
  97. * Old cursor was an animated cursor, so kill the timer that is used
  98. * to animate it.
  99. */
  100. NtUserKillTimer(hwnd, IDSYS_STANIMATE);
  101. }
  102. /*
  103. * Initialize the old-image return value.
  104. */
  105. hImageOld = pstat->hImage;
  106. rc.right = rc.bottom = 0;
  107. if (hImage != NULL) {
  108. switch (bType) {
  109. case SS_ENHMETAFILE: {
  110. /*
  111. * We do NOT resize the window.
  112. */
  113. rc.right = pwnd->rcClient.right - pwnd->rcClient.left;
  114. rc.bottom = pwnd->rcClient.bottom - pwnd->rcClient.top;
  115. break;
  116. }
  117. case SS_BITMAP: {
  118. BITMAP bmp;
  119. if (GetObject(hImage, sizeof(BITMAP), &bmp)) {
  120. rc.right = bmp.bmWidth;
  121. rc.bottom = bmp.bmHeight;
  122. }
  123. }
  124. break;
  125. case SS_ICON: {
  126. NtUserGetIconSize(hImage, 0, &rc.right, &rc.bottom);
  127. rc.bottom /= 2;
  128. pstat->cicur = 0;
  129. pstat->iicur = 0;
  130. if (GetCursorFrameInfo(hImage, NULL, 0, &dwRate, &cicur)) {
  131. fAnimated = (cicur > 1);
  132. pstat->cicur = cicur;
  133. }
  134. }
  135. break;
  136. }
  137. }
  138. pstat->hImage = hImage;
  139. pstat->fDeleteIt = fDeleteIt;
  140. /*
  141. * Resize static to fit. Do NOT do this for SS_CENTERIMAGE or
  142. * SS_REALSIZECONTROL.
  143. */
  144. if (!TestWF(pwnd, SFCENTERIMAGE) && !TestWF(pwnd, SFREALSIZECONTROL)) {
  145. /*
  146. * Get current window rect in parent's client coordinates.
  147. */
  148. GetRect(pwnd, &rcWindow, GRECT_WINDOW | GRECT_PARENTCOORDS);
  149. /*
  150. * Get new window dimensions.
  151. */
  152. rc.left = 0;
  153. rc.top = 0;
  154. if (rc.right && rc.bottom) {
  155. _AdjustWindowRectEx(&rc, pwnd->style, FALSE, pwnd->ExStyle);
  156. rc.right -= rc.left;
  157. rc.bottom -= rc.top;
  158. }
  159. NtUserSetWindowPos(hwnd,
  160. HWND_TOP,
  161. 0,
  162. 0,
  163. rc.right,
  164. rc.bottom,
  165. SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
  166. }
  167. if (TestWF(pwnd, WFVISIBLE)) {
  168. NtUserInvalidateRect(hwnd, NULL, TRUE);
  169. UpdateWindow(hwnd);
  170. }
  171. /*
  172. * If this is an aimated-icon, then start the timer for the animation
  173. * sequence.
  174. */
  175. if(fAnimated) {
  176. GetCursorFrameInfo(pstat->hImage, NULL, pstat->iicur, &dwRate, &cicur);
  177. dwRate = max(200, dwRate * 100 / 6);
  178. NtUserSetTimer(hwnd, IDSYS_STANIMATE, dwRate, NULL);
  179. }
  180. return hImageOld;
  181. }
  182. /***************************************************************************\
  183. * StaticLoadImage
  184. *
  185. * Loads the icon or bitmap from the app's resource file if a name was
  186. * specified in the dialog template. We assume that the name is the name of
  187. * the resource to load.
  188. \***************************************************************************/
  189. VOID xxxStaticLoadImage(
  190. PSTAT pstat,
  191. LPWSTR lpszName)
  192. {
  193. HANDLE hImage = NULL;
  194. PWND pwnd = pstat->spwnd;
  195. CheckLock(pwnd);
  196. if (lpszName && *lpszName) {
  197. /*
  198. * Only try to load the icon/bitmap if the string is non null.
  199. */
  200. if (*(BYTE FAR *)lpszName == 0xFF)
  201. lpszName = MAKEINTRESOURCE(((LPWORD)lpszName)[1]);
  202. /*
  203. * Load the image. If it can't be found in the app, try the
  204. * display driver.
  205. */
  206. if (lpszName) {
  207. switch (TestWF(pwnd, SFTYPEMASK)) {
  208. case SS_BITMAP:
  209. /*
  210. * If the window is not owned by the server, first call
  211. * back out to the client.
  212. */
  213. if (!gfServerProcess && pwnd->hModule) {
  214. hImage = LoadBitmap(KHANDLE_TO_HANDLE(pwnd->hModule), lpszName);
  215. }
  216. /*
  217. * If the above didn't load it, try loading it from the
  218. * display driver (hmod == NULL).
  219. */
  220. if (hImage == NULL) {
  221. hImage = LoadBitmap(NULL, lpszName);
  222. }
  223. break;
  224. case SS_ICON:
  225. if (TestWF(pwnd, SFREALSIZEIMAGE)) {
  226. if (!gfServerProcess && pwnd->hModule) {
  227. hImage = LoadImage(KHANDLE_TO_HANDLE(pwnd->hModule), lpszName, IMAGE_ICON, 0, 0, 0);
  228. }
  229. } else {
  230. /*
  231. * If the window is not owned by the server, first call
  232. * back out to the client. Try loading both icons/cursor
  233. * types.
  234. */
  235. if (!gfServerProcess && pwnd->hModule) {
  236. hImage = LoadIcon(KHANDLE_TO_HANDLE(pwnd->hModule),
  237. lpszName);
  238. /*
  239. * We will also try to load a cursor-format if the
  240. * window is 4.0 compatible. Icons/Cursors are really
  241. * the same. We don't do this for 3.x apps for the
  242. * usual compatibility reasons.
  243. */
  244. if (hImage == NULL && TestWF(pwnd, WFWIN40COMPAT)) {
  245. hImage = LoadCursor(KHANDLE_TO_HANDLE(pwnd->hModule), lpszName);
  246. }
  247. }
  248. /*
  249. * If the above didn't load it, try loading it from the
  250. * display driver (hmod == NULL).
  251. */
  252. if (hImage == NULL) {
  253. hImage = LoadIcon(NULL, lpszName);
  254. }
  255. }
  256. break;
  257. }
  258. /*
  259. * Set the image if it was loaded.
  260. */
  261. if (hImage) {
  262. xxxSetStaticImage(pstat, hImage, TRUE);
  263. }
  264. }
  265. }
  266. }
  267. /***************************************************************************\
  268. * StaticCallback
  269. *
  270. * Draws text statics, called by DrawState.
  271. \***************************************************************************/
  272. BOOL CALLBACK StaticCallback(
  273. HDC hdc,
  274. LPARAM lData,
  275. WPARAM wData,
  276. int cx,
  277. int cy)
  278. {
  279. PWND pwnd = (PWND)lData;
  280. UINT style;
  281. LPWSTR lpszName;
  282. RECT rc;
  283. BYTE bType;
  284. UNREFERENCED_PARAMETER(wData);
  285. bType = TestWF(pwnd, SFTYPEMASK);
  286. UserAssert(rgstk[bType] & STK_USETEXT);
  287. if (pwnd->strName.Length) {
  288. lpszName = REBASE(pwnd, strName.Buffer);
  289. style = DT_NOCLIP | DT_EXPANDTABS;
  290. if (bType != LOBYTE(SS_LEFTNOWORDWRAP)) {
  291. style |= DT_WORDBREAK;
  292. style |= (UINT)(bType - LOBYTE(SS_LEFT));
  293. if (TestWF(pwnd, SFEDITCONTROL)) {
  294. style |= DT_EDITCONTROL;
  295. }
  296. }
  297. switch (TestWF(pwnd, SFELLIPSISMASK)) {
  298. case HIBYTE(LOWORD(SS_ENDELLIPSIS)):
  299. style |= DT_END_ELLIPSIS | DT_SINGLELINE;
  300. break;
  301. case HIBYTE(LOWORD(SS_PATHELLIPSIS)):
  302. style |= DT_PATH_ELLIPSIS | DT_SINGLELINE;
  303. break;
  304. case HIBYTE(LOWORD(SS_WORDELLIPSIS)):
  305. style |= DT_WORD_ELLIPSIS | DT_SINGLELINE;
  306. break;
  307. }
  308. if (TestWF(pwnd, SFNOPREFIX)) {
  309. style |= DT_NOPREFIX;
  310. }
  311. if (TestWF(pwnd, SFCENTERIMAGE)) {
  312. style |= DT_VCENTER | DT_SINGLELINE;
  313. }
  314. rc.left = 0;
  315. rc.top = 0;
  316. rc.right = cx;
  317. rc.bottom = cy;
  318. if (TestWF(pwnd, WEFPUIACCELHIDDEN)) {
  319. style |= DT_HIDEPREFIX;
  320. } else if (((PSTATWND)pwnd)->pstat->fPaintKbdCuesOnly) {
  321. style |= DT_PREFIXONLY;
  322. }
  323. DrawTextExW(hdc, lpszName, -1, &rc, (DWORD)style, NULL);
  324. }
  325. return TRUE;
  326. }
  327. /***************************************************************************\
  328. * xxxStaticPaint
  329. *
  330. * History:
  331. \***************************************************************************/
  332. VOID xxxStaticPaint(
  333. PSTAT pstat,
  334. HDC hdc,
  335. BOOL fClip)
  336. {
  337. PWND pwndParent;
  338. RECT rc;
  339. UINT cmd;
  340. BYTE bType;
  341. BOOL fFont;
  342. HBRUSH hbrControl;
  343. UINT oldAlign;
  344. DWORD dwOldLayout = 0;
  345. HANDLE hfontOld = NULL;
  346. PWND pwnd = pstat->spwnd;
  347. HWND hwnd = HWq(pwnd);
  348. CheckLock(pwnd);
  349. if (TestWF(pwnd, WEFRTLREADING)) {
  350. oldAlign = GetTextAlign(hdc);
  351. SetTextAlign(hdc, oldAlign | TA_RTLREADING);
  352. }
  353. bType = TestWF(pwnd, SFTYPEMASK);
  354. _GetClientRect(pwnd, &rc);
  355. if (fClip) {
  356. IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
  357. }
  358. fFont = (rgstk[bType] & STK_USEFONT) && (pstat->hFont != NULL);
  359. if (fFont) {
  360. hfontOld = SelectObject(hdc, pstat->hFont);
  361. }
  362. /*
  363. * Send WM_CTLCOLORSTATIC to all statics (even frames) for 1.03
  364. * compatibility.
  365. */
  366. SetBkMode(hdc, OPAQUE);
  367. hbrControl = GetControlBrush(hwnd, hdc, WM_CTLCOLORSTATIC);
  368. /*
  369. * Do we erase the background? We don't for SS_OWNERDRAW
  370. * and STK_GRAPHIC kind of things.
  371. */
  372. pwndParent = REBASEPWND(pwnd, spwndParent);
  373. if ((rgstk[bType] & STK_ERASE) && !pstat->fPaintKbdCuesOnly) {
  374. PaintRect(HW(pwndParent), hwnd, hdc, hbrControl, &rc);
  375. }
  376. switch (LOBYTE(bType)) {
  377. case SS_ICON:
  378. if (pstat->hImage) {
  379. int cx;
  380. int cy;
  381. POINT pt;
  382. if (TestWF(pwnd,WEFLAYOUTRTL)) {
  383. dwOldLayout = SetLayoutWidth(hdc, -1, 0);
  384. }
  385. /*
  386. * Perform the correct rect-setup.
  387. */
  388. if (TestWF(pwnd,SFCENTERIMAGE)) {
  389. NtUserGetIconSize(pstat->hImage, pstat->iicur, &cx, &cy);
  390. cy >>= 1;
  391. rc.left = (rc.right - cx) / 2;
  392. rc.right = (rc.left + cx);
  393. rc.top = (rc.bottom - cy) / 2;
  394. rc.bottom = (rc.top + cy);
  395. } else {
  396. cx = rc.right - rc.left;
  397. cy = rc.bottom - rc.top;
  398. }
  399. /*
  400. * Output the icon. If it's animated, we indicate
  401. * the step-frame to output.
  402. */
  403. if (GETFNID(pwndParent) == FNID_DESKTOP) {
  404. SetBrushOrgEx(hdc, 0, 0, &pt);
  405. } else {
  406. SetBrushOrgEx(
  407. hdc,
  408. pwndParent->rcClient.left - pwnd->rcClient.left,
  409. pwndParent->rcClient.top - pwnd->rcClient.top,
  410. &pt);
  411. }
  412. DrawIconEx(hdc, rc.left, rc.top, pstat->hImage, cx, cy,
  413. pstat->iicur, hbrControl, DI_NORMAL);
  414. SetBrushOrgEx(hdc, pt.x, pt.y, NULL);
  415. if (TestWF(pwnd,WEFLAYOUTRTL)) {
  416. SetLayoutWidth(hdc, -1, dwOldLayout);
  417. }
  418. } else {
  419. /*
  420. * Empty! Need to erase.
  421. */
  422. PaintRect(HW(pwndParent), hwnd, hdc, hbrControl, &rc);
  423. }
  424. break;
  425. case SS_BITMAP:
  426. if (pstat->hImage) {
  427. BITMAP bmp;
  428. HBITMAP hbmpT;
  429. RECT rcTmp;
  430. BOOL fErase;
  431. /*
  432. * Get the bitmap information. If this fails, then we
  433. * can assume somethings wrong with its format...don't
  434. * draw in this case.
  435. */
  436. if (GetObject(pstat->hImage, sizeof(BITMAP), &bmp)) {
  437. if (TestWF(pwnd, SFCENTERIMAGE)) {
  438. fErase = ((bmp.bmWidth < rc.right) ||
  439. (bmp.bmHeight < rc.bottom));
  440. rc.left = (rc.right - bmp.bmWidth) >> 1;
  441. rc.right = (rc.left + bmp.bmWidth);
  442. rc.top = (rc.bottom - bmp.bmHeight) >> 1;
  443. rc.bottom = (rc.top + bmp.bmHeight);
  444. } else {
  445. fErase = FALSE;
  446. }
  447. /*
  448. * Select in the bitmap and blt it to the client-surface.
  449. */
  450. RtlEnterCriticalSection(&gcsHdc);
  451. hbmpT = SelectObject(ghdcBits2, pstat->hImage);
  452. StretchBlt(hdc, rc.left, rc.top, rc.right-rc.left,
  453. rc.bottom-rc.top, ghdcBits2, 0, 0, bmp.bmWidth,
  454. bmp.bmHeight, SRCCOPY|NOMIRRORBITMAP);
  455. /*
  456. * Only need to erase the background if the image is
  457. * centered and it's smaller than the client-area.
  458. */
  459. if (fErase) {
  460. HBRUSH hbr;
  461. if (hbr = CreateSolidBrush(GetPixel(ghdcBits2, 0, 0))) {
  462. POLYPATBLT PolyData;
  463. ExcludeClipRect(hdc, rc.left, rc.top,
  464. rc.right, rc.bottom);
  465. _GetClientRect(pwnd, &rcTmp);
  466. PolyData.x = 0;
  467. PolyData.y = 0;
  468. PolyData.cx = rcTmp.right;
  469. PolyData.cy = rcTmp.bottom;
  470. PolyData.BrClr.hbr = hbr;
  471. PolyPatBlt(hdc,PATCOPY,&PolyData,1,PPB_BRUSH);
  472. DeleteObject(hbr);
  473. }
  474. }
  475. if (hbmpT) {
  476. SelectObject(ghdcBits2, hbmpT);
  477. }
  478. RtlLeaveCriticalSection(&gcsHdc);
  479. }
  480. }
  481. break;
  482. case SS_ENHMETAFILE:
  483. if (pstat->hImage) {
  484. RECT rcl;
  485. rcl.left = rc.left;
  486. rcl.top = rc.top;
  487. rcl.right = rc.right;
  488. rcl.bottom = rc.bottom;
  489. PlayEnhMetaFile(hdc, pstat->hImage, &rcl);
  490. }
  491. break;
  492. case SS_OWNERDRAW: {
  493. DRAWITEMSTRUCT dis;
  494. dis.CtlType = ODT_STATIC;
  495. dis.CtlID = PtrToUlong(pwnd->spmenu);
  496. dis.itemAction = ODA_DRAWENTIRE;
  497. dis.itemState = (TestWF(pwnd, WFDISABLED) ? ODS_DISABLED : 0);
  498. dis.hwndItem = hwnd;
  499. dis.hDC = hdc;
  500. dis.itemData = 0L;
  501. dis.rcItem = rc;
  502. if (TestWF(pwnd, WEFPUIACCELHIDDEN)) {
  503. dis.itemState |= ODS_NOACCEL;
  504. }
  505. /*
  506. * Send a WM_DRAWITEM message to the parent.
  507. */
  508. SendMessage(HW(pwndParent), WM_DRAWITEM, (WPARAM)dis.CtlID, (LPARAM)&dis);
  509. }
  510. break;
  511. case SS_LEFT:
  512. case SS_CENTER:
  513. case SS_RIGHT:
  514. case SS_LEFTNOWORDWRAP:
  515. if (pwnd->strName.Length) {
  516. UINT dstFlags;
  517. dstFlags = DST_COMPLEX;
  518. if (TestWF(pwnd, WFDISABLED)) {
  519. dstFlags |= DSS_DISABLED;
  520. }
  521. DrawState(hdc,
  522. SYSHBR(WINDOWTEXT),
  523. StaticCallback,
  524. (LPARAM)pwnd,
  525. (WPARAM)TRUE,
  526. rc.left,
  527. rc.top,
  528. rc.right - rc.left,
  529. rc.bottom - rc.top,
  530. dstFlags);
  531. }
  532. break;
  533. case SS_SIMPLE: {
  534. LPWSTR lpName;
  535. UINT cchName;
  536. /*
  537. * The "Simple" bType assumes everything, including the following:
  538. * 1. The Text exists and fits on one line.
  539. * 2. The Static item is always enabled.
  540. * 3. The Static item is never changed to be a shorter string.
  541. * 4. The Parent never responds to the CTLCOLOR message
  542. */
  543. if (pwnd->strName.Length) {
  544. lpName = REBASE(pwnd, strName.Buffer);
  545. cchName = pwnd->strName.Length / sizeof(WCHAR);
  546. } else {
  547. lpName = (LPWSTR)szNull;
  548. cchName = 0;
  549. }
  550. if (TestWF(pwnd,SFNOPREFIX)) {
  551. ExtTextOut(hdc, rc.left, rc.top, ETO_OPAQUE | ETO_CLIPPED,
  552. &rc, lpName, cchName, 0L);
  553. } else {
  554. /*
  555. * Use OPAQUE for speed.
  556. */
  557. DWORD dwFlags;
  558. if (TestWF(pwnd, WEFPUIACCELHIDDEN)) {
  559. dwFlags = DT_HIDEPREFIX;
  560. } else if (pstat->fPaintKbdCuesOnly) {
  561. dwFlags = DT_PREFIXONLY;
  562. } else {
  563. dwFlags = 0;
  564. }
  565. PSMTextOut(hdc, rc.left, rc.top,
  566. lpName, cchName, dwFlags);
  567. }
  568. }
  569. break;
  570. case SS_BLACKFRAME:
  571. cmd = (COLOR_3DDKSHADOW << 3);
  572. goto StatFrame;
  573. case SS_GRAYFRAME:
  574. cmd = (COLOR_3DSHADOW << 3);
  575. goto StatFrame;
  576. case SS_WHITEFRAME:
  577. cmd = (COLOR_3DHILIGHT << 3);
  578. StatFrame:
  579. DrawFrame(hdc, &rc, 1, cmd);
  580. break;
  581. case SS_BLACKRECT:
  582. hbrControl = SYSHBR(3DDKSHADOW);
  583. goto StatRect;
  584. case SS_GRAYRECT:
  585. hbrControl = SYSHBR(3DSHADOW);
  586. goto StatRect;
  587. case SS_WHITERECT:
  588. hbrControl = SYSHBR(3DHILIGHT);
  589. StatRect:
  590. PaintRect(HW(pwndParent), hwnd, hdc, hbrControl, &rc);
  591. break;
  592. case SS_ETCHEDFRAME:
  593. DrawEdge(hdc, &rc, EDGE_ETCHED, BF_RECT);
  594. break;
  595. }
  596. if (hfontOld) {
  597. SelectObject(hdc, hfontOld);
  598. }
  599. if (TestWF(pwnd, WEFRTLREADING)) {
  600. SetTextAlign(hdc, oldAlign);
  601. }
  602. }
  603. /***************************************************************************\
  604. *
  605. * StaticRepaint()
  606. *
  607. \***************************************************************************/
  608. VOID StaticRepaint(
  609. PSTAT pstat)
  610. {
  611. PWND pwnd = pstat->spwnd;
  612. if (IsVisible(pwnd)) {
  613. HDC hdc;
  614. HWND hwnd = HWq(pwnd);
  615. if (hdc = NtUserGetDC(hwnd)) {
  616. xxxStaticPaint(pstat, hdc, TRUE);
  617. NtUserReleaseDC(hwnd, hdc);
  618. }
  619. }
  620. }
  621. /***************************************************************************\
  622. *
  623. * StaticNotifyParent()
  624. *
  625. * Sends WM_COMMAND notification messages.
  626. *
  627. \***************************************************************************/
  628. // LATER mikeke why do we have multiple versions of notifyparent?
  629. LRESULT FAR PASCAL StaticNotifyParent(
  630. PWND pwnd,
  631. PWND pwndParent,
  632. int nCode)
  633. {
  634. LRESULT lret;
  635. TL tlpwndParent;
  636. UserAssert(pwnd);
  637. if (!pwndParent) {
  638. pwndParent = REBASEPWND(pwnd, spwndParent);
  639. }
  640. ThreadLock(pwndParent, &tlpwndParent);
  641. lret = SendMessage(HW(pwndParent), WM_COMMAND,
  642. MAKELONG(PTR_TO_ID(pwnd->spmenu), nCode), (LPARAM)HWq(pwnd));
  643. ThreadUnlock(&tlpwndParent);
  644. return lret;
  645. }
  646. /***************************************************************************\
  647. * StaticWndProc
  648. *
  649. * History:
  650. \***************************************************************************/
  651. LRESULT APIENTRY StaticWndProcWorker(
  652. PWND pwnd,
  653. UINT message,
  654. WPARAM wParam,
  655. LPARAM lParam,
  656. DWORD fAnsi)
  657. {
  658. HWND hwnd = HWq(pwnd);
  659. BYTE bType;
  660. PSTAT pstat;
  661. static BOOL fInit = TRUE;
  662. CheckLock(pwnd);
  663. VALIDATECLASSANDSIZE(pwnd, FNID_STATIC);
  664. INITCONTROLLOOKASIDE(&StaticLookaside, STAT, spwnd, 8);
  665. /*
  666. * If the control is not interested in this message,
  667. * pass it to DefWindowProc.
  668. */
  669. if (!FWINDOWMSG(message, FNID_STATIC))
  670. return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
  671. /*
  672. * Get the pstat for the given window now since we will use it a lot in
  673. * various handlers. This was stored using SetWindowLong(hwnd,0,pstat) when
  674. * we initially created the static control.
  675. */
  676. pstat = ((PSTATWND)pwnd)->pstat;
  677. /*
  678. * Get the control's type
  679. */
  680. bType = TestWF(pwnd, SFTYPEMASK);
  681. switch (message) {
  682. case STM_GETICON:
  683. wParam = IMAGE_ICON;
  684. case STM_GETIMAGE:
  685. if (IsValidImage(wParam, bType, IMAGE_STMMAX)) {
  686. return (LRESULT)pstat->hImage;
  687. }
  688. break;
  689. case STM_SETICON:
  690. lParam = (LPARAM)wParam;
  691. wParam = IMAGE_ICON;
  692. case STM_SETIMAGE:
  693. if (IsValidImage(wParam, bType, IMAGE_STMMAX)) {
  694. return (LRESULT)xxxSetStaticImage(pstat, (HANDLE)lParam, FALSE);
  695. }
  696. break;
  697. case WM_ERASEBKGND:
  698. /*
  699. * The control will be erased in xxxStaticPaint().
  700. */
  701. return TRUE;
  702. case WM_PRINTCLIENT:
  703. xxxStaticPaint(pstat, (HDC)wParam, FALSE);
  704. break;
  705. case WM_PAINT:
  706. {
  707. HDC hdc;
  708. PAINTSTRUCT ps;
  709. if ((hdc = (HDC)wParam) == NULL) {
  710. hdc = NtUserBeginPaint(hwnd, &ps);
  711. }
  712. if (IsVisible(pwnd)) {
  713. xxxStaticPaint(pstat, hdc, !wParam);
  714. }
  715. /*
  716. * If hwnd was destroyed, BeginPaint was automatically undone.
  717. */
  718. if (!wParam) {
  719. NtUserEndPaint(hwnd, &ps);
  720. }
  721. }
  722. break;
  723. case WM_CREATE:
  724. if ((rgstk[bType] & STK_TYPE) == STK_IMAGE) {
  725. /*
  726. * Pull the name from LPCREATESTRUCT like Win95 does
  727. */
  728. LPWSTR lpszName;
  729. LPSTR lpszAnsiName;
  730. struct {
  731. WORD tag;
  732. BYTE ordLo;
  733. BYTE ordHi;
  734. } dwUnicodeOrdinal;
  735. if (fAnsi) {
  736. /*
  737. * Convert the ANSI string to unicode if it exists.
  738. */
  739. lpszAnsiName = (LPSTR)((LPCREATESTRUCT)lParam)->lpszName;
  740. if (lpszAnsiName) {
  741. if (lpszAnsiName[0] == (CHAR)0xff) {
  742. /*
  743. * Convert ANSI ordinal to UNICODE ordinal
  744. */
  745. dwUnicodeOrdinal.tag = 0xFFFF;
  746. dwUnicodeOrdinal.ordLo = lpszAnsiName[1];
  747. dwUnicodeOrdinal.ordHi = lpszAnsiName[2];
  748. lpszName = (LPWSTR)&dwUnicodeOrdinal;
  749. } else {
  750. MBToWCSEx(0, lpszAnsiName, -1, &lpszName, -1, TRUE);
  751. }
  752. } else {
  753. lpszName = NULL;
  754. }
  755. } else {
  756. lpszName = (LPWSTR)(((LPCREATESTRUCT)lParam)->lpszName);
  757. }
  758. /*
  759. * Load the image
  760. */
  761. xxxStaticLoadImage(pstat, lpszName);
  762. if (fAnsi && lpszName && lpszName != (LPWSTR)&dwUnicodeOrdinal) {
  763. /*
  764. * Free the converted ANSI string.
  765. */
  766. UserLocalFree(lpszName);
  767. }
  768. } else if (bType == SS_ETCHEDHORZ || bType == SS_ETCHEDVERT) {
  769. /*
  770. * Resize static window to fit edge. Horizontal dudes make
  771. * bottom one edge from top, vertical dudes make right edge one
  772. * edge from left.
  773. */
  774. RECT rcClient;
  775. _GetClientRect(pwnd, &rcClient);
  776. if (bType == SS_ETCHEDHORZ) {
  777. rcClient.bottom = SYSMET(CYEDGE);
  778. } else {
  779. rcClient.right = SYSMET(CXEDGE);
  780. }
  781. NtUserSetWindowPos(hwnd,
  782. HWND_TOP,
  783. 0,
  784. 0,
  785. rcClient.right,
  786. rcClient.bottom,
  787. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  788. }
  789. break;
  790. case WM_DESTROY:
  791. if (((rgstk[bType] & STK_TYPE) == STK_IMAGE) &&
  792. (pstat->hImage != NULL) &&
  793. (pstat->fDeleteIt)) {
  794. if (bType == SS_BITMAP) {
  795. DeleteObject(pstat->hImage);
  796. } else if (bType == SS_ICON) {
  797. if (pstat->cicur > 1) {
  798. /*
  799. * Kill the animated cursor timer
  800. */
  801. NtUserKillTimer(hwnd, IDSYS_STANIMATE);
  802. }
  803. NtUserDestroyCursor((HCURSOR)(pstat->hImage), CURSOR_CALLFROMCLIENT);
  804. }
  805. }
  806. break;
  807. case WM_NCCREATE:
  808. if (TestWF(pwnd,WEFRIGHT)) {
  809. NtUserAlterWindowStyle(hwnd, SS_TYPEMASK, SS_RIGHT);
  810. }
  811. if (TestWF(pwnd, SFSUNKEN) ||
  812. ((bType == LOBYTE(SS_ETCHEDHORZ)) || (bType == LOBYTE(SS_ETCHEDVERT)))) {
  813. SetWindowState(pwnd, WEFSTATICEDGE);
  814. }
  815. goto CallDWP;
  816. case WM_NCDESTROY:
  817. case WM_FINALDESTROY:
  818. if (pstat) {
  819. Unlock(&pstat->spwnd);
  820. FreeLookasideEntry(&StaticLookaside, pstat);
  821. }
  822. NtUserSetWindowFNID(hwnd, FNID_CLEANEDUP_BIT);
  823. break;
  824. case WM_NCHITTEST:
  825. return (TestWF(pwnd, SFNOTIFY) ? HTCLIENT : HTTRANSPARENT);
  826. case WM_LBUTTONDOWN:
  827. case WM_NCLBUTTONDOWN:
  828. if (TestWF(pwnd, SFNOTIFY)) {
  829. /*
  830. * It is acceptable for an app to destroy a static label
  831. * in response to a STN_CLICKED notification.
  832. */
  833. StaticNotifyParent(pwnd, NULL, STN_CLICKED);
  834. }
  835. break;
  836. case WM_LBUTTONDBLCLK:
  837. case WM_NCLBUTTONDBLCLK:
  838. if (TestWF(pwnd, SFNOTIFY)) {
  839. /*
  840. * It is acceptable for an app to destroy a static label in
  841. * response to a STN_DBLCLK notification.
  842. */
  843. StaticNotifyParent(pwnd, NULL, STN_DBLCLK);
  844. }
  845. break;
  846. case WM_SETTEXT:
  847. /*
  848. * No more hack to set icon/bitmap via WM_SETTEXT!
  849. */
  850. if (rgstk[bType] & STK_USETEXT) {
  851. if (_DefSetText(hwnd, (LPWSTR)lParam, fAnsi)) {
  852. StaticRepaint(pstat);
  853. return TRUE;
  854. }
  855. }
  856. break;
  857. case WM_ENABLE:
  858. StaticRepaint(pstat);
  859. if (TestWF(pwnd, SFNOTIFY)) {
  860. StaticNotifyParent(pwnd, NULL, (wParam ? STN_ENABLE : STN_DISABLE));
  861. }
  862. break;
  863. case WM_GETDLGCODE:
  864. return (LONG)DLGC_STATIC;
  865. case WM_SETFONT:
  866. /*
  867. * wParam - handle to the font
  868. * lParam - if true, redraw else don't
  869. */
  870. if (rgstk[bType] & STK_USEFONT) {
  871. pstat->hFont = (HANDLE)wParam;
  872. if (lParam && TestWF(pwnd, WFVISIBLE)) {
  873. NtUserInvalidateRect(hwnd, NULL, TRUE);
  874. UpdateWindow(hwnd);
  875. }
  876. }
  877. break;
  878. case WM_GETFONT:
  879. if (rgstk[bType] & STK_USEFONT) {
  880. return (LRESULT)pstat->hFont;
  881. }
  882. break;
  883. case WM_TIMER:
  884. if (wParam == IDSYS_STANIMATE) {
  885. xxxNextAniIconStep(pstat);
  886. }
  887. break;
  888. /*
  889. * case WM_GETTEXT:
  890. * No more hack to get icon/bitmap via WM_GETTEXT!
  891. */
  892. case WM_INPUTLANGCHANGEREQUEST:
  893. if (IS_IME_ENABLED() || IS_MIDEAST_ENABLED()) {
  894. /*
  895. * #115190
  896. * If the window is one of controls on top of dialogbox,
  897. * let the parent dialog handle it.
  898. */
  899. if (TestwndChild(pwnd) && pwnd->spwndParent) {
  900. PWND pwndParent = REBASEALWAYS(pwnd, spwndParent);
  901. if (pwndParent) {
  902. PCLS pclsParent = REBASEALWAYS(pwndParent, pcls);
  903. UserAssert(pclsParent != NULL);
  904. if (pclsParent->atomClassName == gpsi->atomSysClass[ICLS_DIALOG]) {
  905. return SendMessageWorker(pwndParent, message, wParam, lParam, FALSE);
  906. }
  907. }
  908. }
  909. }
  910. goto CallDWP;
  911. case WM_UPDATEUISTATE:
  912. {
  913. /*
  914. * DWP will change the UIState bits accordingly
  915. */
  916. DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
  917. if (HIWORD(wParam) & UISF_HIDEACCEL) {
  918. /*
  919. * Change in AccelHidden state: need to repaint
  920. */
  921. if (ISSSTEXTOROD(bType)) {
  922. pstat->fPaintKbdCuesOnly = TRUE;
  923. StaticRepaint(pstat);
  924. pstat->fPaintKbdCuesOnly = FALSE;
  925. }
  926. }
  927. }
  928. break;
  929. default:
  930. CallDWP:
  931. return DefWindowProcWorker(pwnd, message, wParam, lParam, fAnsi);
  932. }
  933. return 0;
  934. }
  935. LRESULT WINAPI StaticWndProcA(
  936. HWND hwnd,
  937. UINT message,
  938. WPARAM wParam,
  939. LPARAM lParam)
  940. {
  941. PWND pwnd;
  942. if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
  943. return 0;
  944. }
  945. return StaticWndProcWorker(pwnd, message, wParam, lParam, TRUE);
  946. }
  947. LRESULT WINAPI StaticWndProcW(
  948. HWND hwnd,
  949. UINT message,
  950. WPARAM wParam,
  951. LPARAM lParam)
  952. {
  953. PWND pwnd;
  954. if ((pwnd = ValidateHwnd(hwnd)) == NULL) {
  955. return 0;
  956. }
  957. return StaticWndProcWorker(pwnd, message, wParam, lParam, FALSE);
  958. }
  959. /***************************************************************************\
  960. * Next Animated Icon Step
  961. *
  962. * Advances to the next step in an animaged icon.
  963. \***************************************************************************/
  964. VOID xxxNextAniIconStep(
  965. PSTAT pstat)
  966. {
  967. DWORD dwRate;
  968. PWND pwnd = pstat->spwnd;
  969. HWND hwnd = HWq(pwnd);
  970. /*
  971. * Stop the timer for the next animation step.
  972. */
  973. NtUserKillTimer(hwnd, IDSYS_STANIMATE);
  974. if (++(pstat->iicur) >= pstat->cicur) {
  975. pstat->iicur = 0;
  976. }
  977. GetCursorFrameInfo(pstat->hImage, NULL, pstat->iicur, &dwRate, &pstat->cicur);
  978. dwRate = max(200, dwRate * 100 / 6);
  979. NtUserInvalidateRect(hwnd, NULL, FALSE);
  980. UpdateWindow(hwnd);
  981. NtUserSetTimer(hwnd, IDSYS_STANIMATE, dwRate, NULL);
  982. }