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.

1386 lines
42 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: caption.c (aka wmcap.c)
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * History:
  7. * 28-Oct-1990 MikeHar Ported functions from Win 3.0 sources.
  8. * 01-Feb-1991 MikeKe Added Revalidation code (None)
  9. * 03-Jan-1992 IanJa Neutralized (ANSI/wide-character)
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #define MIN 0x01
  14. #define MAX 0x02
  15. #define NOMIN 0x04
  16. #define NOMAX 0x08
  17. #define NOCLOSE 0x10
  18. #define SMCAP 0x20
  19. #define NOSIZE (NOMIN | NOMAX)
  20. /***************************************************************************\
  21. * xxxCalcCaptionButton
  22. *
  23. * This calculates the location of the caption button.
  24. \***************************************************************************/
  25. DWORD xxxCalcCaptionButton(
  26. PWND pwnd,
  27. int iButton,
  28. LPWORD pcmd,
  29. LPRECT prcBtn,
  30. LPWORD pbm)
  31. {
  32. int x, y, cBorders, cxS, cyS;
  33. CheckLock(pwnd);
  34. *pcmd = 0;
  35. if (TestWF(pwnd, WFMINIMIZED)) {
  36. x = -SYSMET(CXFIXEDFRAME);
  37. y = -SYSMET(CYFIXEDFRAME);
  38. } else {
  39. cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE);
  40. x = -cBorders * SYSMET(CXBORDER);
  41. y = -cBorders * SYSMET(CYBORDER);
  42. }
  43. CopyInflateRect(prcBtn, &pwnd->rcWindow, x, y);
  44. x = -pwnd->rcWindow.left;
  45. y = -pwnd->rcWindow.top;
  46. /*
  47. * Get real caption area: Subtract final border underneath caption that
  48. * separates it from everything else.
  49. */
  50. if (TestWF(pwnd, WEFTOOLWINDOW)) {
  51. cxS = SYSMET(CXSMSIZE);
  52. cyS = SYSMET(CYSMSIZE);
  53. } else {
  54. cxS = SYSMET(CXSIZE);
  55. cyS = SYSMET(CYSIZE);
  56. }
  57. if (iButton == INDEX_TITLEBAR_CLOSEBUTTON) {
  58. if (xxxMNCanClose(pwnd)) {
  59. *pbm = TestWF(pwnd, WEFTOOLWINDOW) ? OBI_CLOSE_PAL : OBI_CLOSE;
  60. *pcmd = SC_CLOSE;
  61. }
  62. } else if (iButton == INDEX_TITLEBAR_MINBUTTON) {
  63. /*
  64. * Reduce button isn't last button, so shift left by one button
  65. */
  66. if (TestWF(pwnd, WFMINBOX)) {
  67. prcBtn->right -= cxS * 2;
  68. x += SYSMET(CXEDGE);
  69. if (TestWF(pwnd, WFMINIMIZED)) {
  70. *pbm = OBI_RESTORE;
  71. *pcmd = SC_RESTORE;
  72. } else {
  73. *pbm = OBI_REDUCE;
  74. *pcmd = SC_MINIMIZE;
  75. }
  76. }
  77. } else if (iButton == INDEX_TITLEBAR_MAXBUTTON) {
  78. if (TestWF(pwnd, WFMAXBOX)) {
  79. prcBtn->right -= cxS;
  80. if (TestWF(pwnd, WFMAXIMIZED)) {
  81. *pbm = OBI_RESTORE;
  82. *pcmd = SC_RESTORE;
  83. } else {
  84. *pbm = OBI_ZOOM;
  85. *pcmd = SC_MAXIMIZE;
  86. }
  87. }
  88. } else {
  89. if (TestWF(pwnd, WEFCONTEXTHELP)) {
  90. prcBtn->right -= cxS;
  91. *pbm = OBI_HELP;
  92. *pcmd = SC_CONTEXTHELP;
  93. }
  94. }
  95. if (*pcmd) {
  96. prcBtn->bottom = prcBtn->top + cyS;
  97. prcBtn->left = prcBtn->right - cxS;
  98. /*
  99. * Adjust 'x' and 'y' to window coordinates
  100. */
  101. x += prcBtn->left;
  102. y += prcBtn->top + SYSMET(CYEDGE);
  103. /*
  104. * rcBtn (screen coords hit rect) has a one-border tolerance all
  105. * around
  106. */
  107. InflateRect(prcBtn, SYSMET(CXBORDER), SYSMET(CYBORDER));
  108. if (TestWF(pwnd, WEFLAYOUTRTL)) {
  109. cxS = prcBtn->right - prcBtn->left;
  110. prcBtn->right = pwnd->rcWindow.right - (prcBtn->left - pwnd->rcWindow.left);
  111. prcBtn->left = prcBtn->right - cxS;
  112. }
  113. }
  114. return (DWORD)MAKELONG(x, y);
  115. }
  116. /***************************************************************************\
  117. * xxxTrackCaptionButton
  118. *
  119. * Handles clicking and dragging on caption buttons. We draw the button
  120. * depressed then track the mouse. If the user moves outside of the button,
  121. * undepress it. When the mouse button is finally released, we return whether
  122. * the mouse was inside the button or not. I.E., whether the button was
  123. * clicked.
  124. \***************************************************************************/
  125. WORD xxxTrackCaptionButton(
  126. PWND pwnd,
  127. UINT hit)
  128. {
  129. WORD cmd;
  130. MSG msg;
  131. HDC hdc;
  132. WORD bm;
  133. int x;
  134. int y;
  135. WORD wState;
  136. WORD wNewState;
  137. BOOL fMouseUp = FALSE;
  138. RECT rcBtn;
  139. DWORD dwWhere;
  140. int iButton;
  141. WORD wf;
  142. UserAssert(IsWinEventNotifyDeferredOK());
  143. CheckLock(pwnd);
  144. /*
  145. * Set up iButton for this and future STATECHANGE events
  146. */
  147. switch (hit) {
  148. case HTCLOSE:
  149. iButton = INDEX_TITLEBAR_CLOSEBUTTON;
  150. wf = WFCLOSEBUTTONDOWN;
  151. break;
  152. case HTREDUCE:
  153. iButton = INDEX_TITLEBAR_MINBUTTON;
  154. wf = WFREDUCEBUTTONDOWN;
  155. break;
  156. case HTZOOM:
  157. iButton = INDEX_TITLEBAR_MAXBUTTON;
  158. wf = WFZOOMBUTTONDOWN;
  159. break;
  160. case HTHELP:
  161. iButton = INDEX_TITLEBAR_HELPBUTTON;
  162. wf = WFHELPBUTTONDOWN;
  163. break;
  164. default:
  165. UserAssert(FALSE);
  166. }
  167. dwWhere = xxxCalcCaptionButton(pwnd, iButton, &cmd, &rcBtn, &bm);
  168. x = GET_X_LPARAM(dwWhere);
  169. y = GET_Y_LPARAM(dwWhere);
  170. if (cmd) {
  171. /*
  172. * Draw the image in its depressed state.
  173. */
  174. hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_USESTYLE);
  175. BitBltSysBmp(hdc, x, y, bm + DOBI_PUSHED);
  176. _ReleaseDC(hdc);
  177. wState = DOBI_PUSHED;
  178. /*
  179. * Notification of button press.
  180. */
  181. SetWF(pwnd, wf);
  182. xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_TITLEBAR, iButton, 0);
  183. } else {
  184. iButton = 0;
  185. }
  186. xxxSetCapture(pwnd);
  187. while (!fMouseUp) {
  188. if (xxxPeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)) {
  189. if (msg.message == WM_LBUTTONUP) {
  190. xxxReleaseCapture();
  191. fMouseUp = TRUE;
  192. } else if ((msg.message == WM_MOUSEMOVE) && cmd) {
  193. wNewState = PtInRect(&rcBtn, msg.pt) ? DOBI_PUSHED : DOBI_NORMAL;
  194. if (wState != wNewState) {
  195. wState = wNewState;
  196. hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_USESTYLE);
  197. BitBltSysBmp(hdc, x, y, bm + wState);
  198. _ReleaseDC(hdc);
  199. if (wState == DOBI_PUSHED) {
  200. SetWF(pwnd, wf);
  201. } else {
  202. ClrWF(pwnd, wf);
  203. }
  204. xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_TITLEBAR, iButton, 0);
  205. }
  206. }
  207. } else if (!xxxSleepThread(QS_MOUSE, 0, TRUE)) {
  208. break;
  209. }
  210. if (pwnd != PtiCurrent()->pq->spwndCapture) {
  211. /*
  212. * We lost capture. This could have happened during
  213. * the WM_CAPTURECHANGED callback or later if we
  214. * are/were not in the foreground queue.
  215. */
  216. break;
  217. }
  218. }
  219. if (!cmd) {
  220. return 0;
  221. }
  222. if (wState && (cmd != SC_CONTEXTHELP)) {
  223. hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_USESTYLE);
  224. BitBltSysBmp(hdc, x, y, bm);
  225. _ReleaseDC(hdc);
  226. ClrWF(pwnd, wf);
  227. xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_TITLEBAR, iButton, 0);
  228. }
  229. return (fMouseUp && PtInRect(&rcBtn, msg.pt)) ? cmd : 0;
  230. }
  231. /***************************************************************************\
  232. * xxxGetWindowSmIcon
  233. *
  234. * Gets icon to draw in caption of window.
  235. \***************************************************************************/
  236. PCURSOR xxxGetWindowSmIcon(
  237. PWND pwnd,
  238. BOOL fDontSendMsg)
  239. {
  240. PCURSOR pcursor = NULL;
  241. HICON hico = NULL;
  242. PCLS pcls = pwnd->pcls;
  243. CheckLock(pwnd);
  244. /*
  245. * We check per-window stuff first then per-class stuff, preferring a
  246. * real small icon over a stretched big one.
  247. *
  248. * Per-window small icon
  249. * Per-window big icon stretched small
  250. * Per-class small icon
  251. * Per-class big icon stretched small
  252. * WM_QUERYDRAGICON big icon stretched small (for 3.x dudes)
  253. *
  254. * Try window small icon first
  255. * NOTE: The WM_SETICON and WM_GETICON messags are for ISVs only.
  256. */
  257. if ((hico = (HICON)_GetProp(pwnd, MAKEINTATOM(gpsi->atomIconSmProp), PROPF_INTERNAL)) != NULL) {
  258. if (pcursor = (PCURSOR)HMValidateHandleNoSecure(hico, TYPE_CURSOR)) {
  259. return pcursor;
  260. } else {
  261. RIPMSG1(RIP_WARNING,"GetWindowSmIcon: Invalid small icon handle (0x%p)", hico);
  262. }
  263. }
  264. /*
  265. * Try class small icon next.
  266. */
  267. pcursor = pcls->spicnSm; {
  268. if (pcursor != NULL)
  269. return pcursor;
  270. }
  271. if (!TestWF(pwnd, WFWIN40COMPAT) &&
  272. (!TestWF(pwnd, WFOLDUI) ||
  273. !TestWF(pwnd, WEFMDICHILD)) &&
  274. !fDontSendMsg) {
  275. ULONG_PTR dwResult;
  276. /*
  277. * A few old apps like Corel don't set their class icon and other
  278. * data until long after we need it. If we send them WM_QUERYDRAGICON,
  279. * they will fault because they don't check the return from GWL to
  280. * get their data. WFOLDUI apps won't ever get a WM_QUERYDRAGICON,
  281. * sorry. Currently the apps with this hack (not for this reason
  282. * necessarily)
  283. * Corel Photo-Paint 5.0
  284. * Myst 2.0
  285. * Visual Baler 3.0
  286. * Quicken
  287. */
  288. if (xxxSendMessageTimeout(pwnd,
  289. WM_QUERYDRAGICON,
  290. 0,
  291. 0,
  292. SMTO_NORMAL,
  293. 100,
  294. &dwResult)) {
  295. hico = (HICON)dwResult;
  296. }
  297. if (hico) {
  298. hico = xxxCreateWindowSmIcon(pwnd, hico, FALSE);
  299. pcursor = (PCURSOR)HMValidateHandleNoSecure(hico, TYPE_CURSOR);
  300. if (pcursor == NULL) {
  301. hico = NULL;
  302. }
  303. }
  304. }
  305. if (pcursor == NULL) {
  306. pcursor = SYSICO(WINLOGO);
  307. }
  308. return pcursor;
  309. }
  310. /***************************************************************************\
  311. * BltMe4Times
  312. *
  313. * This routine blts out two copies of the specified caption icon. One for an
  314. * active window and one for an inactive window.
  315. \***************************************************************************/
  316. VOID BltMe4Times(
  317. POEMBITMAPINFO pOem,
  318. int cxySlot,
  319. int cxyIcon,
  320. HDC hdcSrc,
  321. PCURSOR pcursor,
  322. UINT flags)
  323. {
  324. RECT rc;
  325. int i;
  326. int j;
  327. BOOL fMask = TRUE;
  328. LONG rop;
  329. HBRUSH hBrush;
  330. hBrush = (flags & DC_INBUTTON) ? SYSHBR(3DHILIGHT) : SYSHBR(ACTIVECAPTION);
  331. for (i = 0; i < 2; i++) {
  332. rop = SRCAND;
  333. rc.left = pOem->x;
  334. rc.top = pOem->y;
  335. rc.right = rc.left + pOem->cx;
  336. rc.bottom = rc.top + pOem->cy;
  337. FillRect(HDCBITS(), &rc, hBrush);
  338. rc.top += (cxySlot - cxyIcon) / 2;
  339. rc.left += SYSMET(CXBORDER) + (cxySlot - cxyIcon) / 2;
  340. for (j = 0; j < 2; j++) {
  341. BltIcon(
  342. HDCBITS(),
  343. rc.left,
  344. rc.top,
  345. cxyIcon,
  346. cxyIcon,
  347. hdcSrc,
  348. pcursor,
  349. fMask ? DI_MASK : DI_IMAGE,
  350. rop);
  351. fMask = !fMask;
  352. rop = SRCINVERT;
  353. }
  354. pOem += DOBI_CAPOFF;
  355. hBrush = (flags & DC_INBUTTON) ? SYSHBR(3DFACE) : SYSHBR(INACTIVECAPTION);
  356. }
  357. }
  358. /***************************************************************************\
  359. * DrawCaptionIcon
  360. *
  361. * In order to speed up the drawing of caption icons a cache is maintained.
  362. * Within the cache, the first entry, 0, is for the tray's depressed caption
  363. * look. Items 1..CCACHEDCAPTIONS are for the actual caption's icons.
  364. \***************************************************************************/
  365. VOID DrawCaptionIcon(
  366. HDC hdc,
  367. LPRECT lprc,
  368. PCURSOR pcursor,
  369. HBRUSH hbrFill,
  370. UINT flags)
  371. {
  372. int i;
  373. int xStart = 0;
  374. int cxySlot;
  375. POEMBITMAPINFO pOem;
  376. RECT rc;
  377. CAPTIONCACHE ccTemp;
  378. /*
  379. * Check the size of the icon to see if it matches the size of the
  380. * cache we created. Most of the time this will match. Also, if
  381. * we are drawing with DC_INBUTTON in 16 colors, don't cache. Also,
  382. * if the icon has an active alpha channel, just blit it directly
  383. * and don't cache!
  384. */
  385. cxySlot = lprc->bottom - lprc->top;
  386. if ((cxySlot != gpsi->oembmi[OBI_CAPCACHE1].cy) ||
  387. (hbrFill == gpsi->hbrGray) ||
  388. (pcursor->hbmUserAlpha != NULL)) {
  389. rc.left = lprc->left;
  390. rc.top = lprc->top;
  391. rc.right = lprc->left + cxySlot;
  392. rc.bottom = lprc->top + cxySlot;
  393. FillRect(hdc, &rc, hbrFill);
  394. rc.left += SYSMET(CXBORDER) + (cxySlot - SYSMET(CXSMICON)) / 2;
  395. rc.top += (cxySlot - SYSMET(CYSMICON)) / 2;
  396. _DrawIconEx(hdc,
  397. rc.left,
  398. rc.top,
  399. pcursor,
  400. SYSMET(CXSMICON),
  401. SYSMET(CYSMICON),
  402. 0,
  403. NULL,
  404. DI_NORMAL);
  405. goto Done;
  406. }
  407. if (flags & DC_INBUTTON) {
  408. /*
  409. * The DC_INBUTTON icons is always slot 0.
  410. */
  411. i = ((gcachedCaptions[0].spcursor == pcursor) ? 0 : CCACHEDCAPTIONS);
  412. } else {
  413. /*
  414. * Search the cache to see if this cursor is currently cached.
  415. */
  416. for (i = 1; i < CCACHEDCAPTIONS; i++) {
  417. if (gcachedCaptions[i].spcursor == pcursor) {
  418. break;
  419. }
  420. }
  421. }
  422. if (i >= CCACHEDCAPTIONS) {
  423. /*
  424. * Icon wasn't cached, so try and add it to the cache.
  425. */
  426. if (flags & DC_INBUTTON) {
  427. /*
  428. * The tray's special DC_INBUTTON style always goes in slot 0.
  429. */
  430. i = 0;
  431. } else {
  432. /*
  433. * Look for an empty slot in the cache. If we can't find one,
  434. * stuff the new icon at the end of the cache. The result will
  435. * be that the last item will be deleted.
  436. */
  437. for (i = 1; i < CCACHEDCAPTIONS - 1; i++) {
  438. if (gcachedCaptions[i].spcursor == NULL)
  439. break;
  440. }
  441. }
  442. /*
  443. * Add an item to the cache by blting an active and inactive copy of
  444. * the icon.
  445. */
  446. BltMe4Times(gcachedCaptions[i].pOem,
  447. cxySlot,
  448. SYSMET(CXSMICON),
  449. ghdcMem,
  450. pcursor,
  451. flags);
  452. Lock(&(gcachedCaptions[i].spcursor), pcursor);
  453. #if DBG
  454. gcachedCaptions[i].hico = (HICON)PtoH(pcursor);
  455. #endif
  456. }
  457. /*
  458. * We have a hit, so move that cached icon to the front of the cache.
  459. * This means that the least recently used icon will be the last icon in
  460. * the cache. Remember, we never update index 0 because it is reserved
  461. * for the DC_INBUTTON icon.
  462. */
  463. for ( ; i > 1; i-- ) {
  464. /*
  465. * Move the entry toward the front.
  466. */
  467. ccTemp = gcachedCaptions[i];
  468. gcachedCaptions[i] = gcachedCaptions[i - 1];
  469. gcachedCaptions[i - 1] = ccTemp;
  470. #if DBG
  471. /*
  472. * In checked builds we need to adjust the lock records for the
  473. * cursor so it has the correct address.
  474. */
  475. if (IsDbgTagEnabled(DBGTAG_TrackLocks)) {
  476. if (gcachedCaptions[i].spcursor) {
  477. HMRelocateLockRecord(&(gcachedCaptions[i].spcursor), (int)sizeof(CAPTIONCACHE));
  478. }
  479. if (gcachedCaptions[i - 1].spcursor) {
  480. HMRelocateLockRecord(&(gcachedCaptions[i - 1].spcursor), -(int)sizeof(CAPTIONCACHE));
  481. }
  482. }
  483. #endif
  484. }
  485. /*
  486. * Make sure the icon we want to draw is the one that we hit in the
  487. * cache.
  488. */
  489. UserAssert(gcachedCaptions[i].hico == PtoH(pcursor));
  490. /*
  491. * Determine what cached bitmap to blt.
  492. */
  493. pOem = gcachedCaptions[i].pOem;
  494. if (!(flags & DC_ACTIVE)) {
  495. pOem += DOBI_CAPOFF;
  496. }
  497. GreBitBlt(hdc,
  498. lprc->left,
  499. lprc->top,
  500. cxySlot,
  501. cxySlot,
  502. HDCBITS(),
  503. pOem->x,
  504. pOem->y,
  505. SRCCOPY,
  506. 0);
  507. Done:
  508. /*
  509. * Adjust the given rectangle for the icon we just drew
  510. */
  511. lprc->left += cxySlot;
  512. }
  513. /***************************************************************************\
  514. * FillGradient
  515. *
  516. * The rectangle is broken into two triangles: {0, 1, 2} and {0, 2, 3}.
  517. * Color on {0, 3} is black, and on {1, 2) is the active caption color.
  518. *
  519. * 0 1
  520. * 3 2
  521. *
  522. * 12/06/96 vadimg created
  523. \***************************************************************************/
  524. VOID FillGradient(
  525. HDC hdc,
  526. LPCRECT prc,
  527. COLORREF rgbLeft,
  528. COLORREF rgbRight)
  529. {
  530. TRIVERTEX avert[4];
  531. static GRADIENT_RECT auRect[1] = {0,1};
  532. #define GetCOLOR16(RGB, clr) ((COLOR16)(Get ## RGB ## Value(clr) << 8))
  533. avert[0].Red = GetCOLOR16(R, rgbLeft);
  534. avert[0].Green = GetCOLOR16(G, rgbLeft);
  535. avert[0].Blue = GetCOLOR16(B, rgbLeft);
  536. avert[1].Red = GetCOLOR16(R, rgbRight);
  537. avert[1].Green = GetCOLOR16(G, rgbRight);
  538. avert[1].Blue = GetCOLOR16(B, rgbRight);
  539. avert[0].x = prc->left;
  540. avert[0].y = prc->top;
  541. avert[1].x = prc->right;
  542. avert[1].y = prc->bottom;
  543. GreGradientFill(hdc, avert, 2,(PVOID)auRect, 1, GRADIENT_FILL_RECT_H);
  544. }
  545. VOID FillCaptionGradient(
  546. HDC hdc,
  547. LPCRECT prc,
  548. BOOL fActive)
  549. {
  550. COLORREF rgbLeft, rgbRight;
  551. if (fActive) {
  552. rgbLeft = gpsi->argbSystem[COLOR_ACTIVECAPTION];
  553. rgbRight = gpsi->argbSystem[COLOR_GRADIENTACTIVECAPTION];
  554. } else {
  555. rgbLeft = gpsi->argbSystem[COLOR_INACTIVECAPTION];
  556. rgbRight = gpsi->argbSystem[COLOR_GRADIENTINACTIVECAPTION];
  557. }
  558. if (rgbLeft != rgbRight) {
  559. FillGradient(hdc, prc, rgbLeft, rgbRight);
  560. } else {
  561. FillRect(hdc, prc, fActive ? SYSHBR(ACTIVECAPTION) : SYSHBR(INACTIVECAPTION));
  562. }
  563. }
  564. /***************************************************************************\
  565. * xxxDrawCaptionTemp
  566. \***************************************************************************/
  567. BOOL xxxDrawCaptionTemp(
  568. PWND pwnd,
  569. HDC hdc,
  570. LPRECT lprc,
  571. HFONT hFont,
  572. PCURSOR pcursor,
  573. PUNICODE_STRING pstrText,
  574. UINT flags)
  575. {
  576. int iOldMode;
  577. HBRUSH hbrFill;
  578. LONG clrOldText;
  579. LONG clrOldBk;
  580. BOOL fItFit = TRUE;
  581. BOOL fGradient = FALSE;
  582. SIZE size;
  583. UINT oldAlign;
  584. CheckLock(pwnd);
  585. if (lprc->right <= lprc->left) {
  586. return FALSE;
  587. }
  588. if (pwnd != NULL) {
  589. if (!pcursor &&
  590. _HasCaptionIcon(pwnd) &&
  591. !(flags & DC_SMALLCAP) &&
  592. TestWF(pwnd, WFSYSMENU)) {
  593. /*
  594. * Only get the icon if we can send messages AND the window has
  595. * a system menu.
  596. */
  597. pcursor = xxxGetWindowSmIcon(pwnd, (flags & DC_NOSENDMSG));
  598. }
  599. }
  600. /*
  601. * Set up the colors.
  602. */
  603. if (flags & DC_ACTIVE) {
  604. if (flags & DC_INBUTTON) {
  605. if (gpsi->BitCount < 8 ||
  606. SYSRGB(3DHILIGHT) != SYSRGB(SCROLLBAR) ||
  607. SYSRGB(3DHILIGHT) == SYSRGB(WINDOW)) {
  608. clrOldText = SYSRGB(3DFACE);
  609. clrOldBk = SYSRGB(3DHILIGHT);
  610. hbrFill = gpsi->hbrGray;
  611. iOldMode = GreSetBkMode(hdc, TRANSPARENT);
  612. } else {
  613. clrOldText = SYSRGB(BTNTEXT);
  614. clrOldBk = SYSRGB(3DHILIGHT);
  615. hbrFill = SYSHBR(3DHILIGHT);
  616. }
  617. } else {
  618. clrOldText = SYSRGB(CAPTIONTEXT);
  619. clrOldBk = SYSRGB(ACTIVECAPTION);
  620. hbrFill = SYSHBR(ACTIVECAPTION);
  621. if (flags & DC_GRADIENT) {
  622. fGradient = TRUE;
  623. iOldMode = GreSetBkMode(hdc, TRANSPARENT);
  624. }
  625. }
  626. } else {
  627. if (flags & DC_INBUTTON) {
  628. clrOldText = SYSRGB(BTNTEXT);
  629. clrOldBk = SYSRGB(3DFACE);
  630. hbrFill = SYSHBR(3DFACE);
  631. } else {
  632. clrOldText = SYSRGB(INACTIVECAPTIONTEXT);
  633. clrOldBk = SYSRGB(INACTIVECAPTION);
  634. hbrFill = SYSHBR(INACTIVECAPTION);
  635. if (flags & DC_GRADIENT) {
  636. fGradient = TRUE;
  637. iOldMode = GreSetBkMode(hdc, TRANSPARENT);
  638. }
  639. }
  640. }
  641. /*
  642. * Set up drawing colors.
  643. */
  644. clrOldText = GreSetTextColor(hdc, clrOldText);
  645. clrOldBk = GreSetBkColor(hdc, clrOldBk);
  646. if (pcursor && !(flags & DC_SMALLCAP)) {
  647. if (flags & DC_ICON) {
  648. /*
  649. * Preserve icon shape when BitBlitting it to a
  650. * mirrored DC. This way we don't violate copyright
  651. * issues on icons. [samera]
  652. */
  653. DWORD dwLayout=0L;
  654. if ((dwLayout=GreGetLayout(hdc)) & LAYOUT_RTL) {
  655. GreSetLayout(hdc, -1, dwLayout|LAYOUT_BITMAPORIENTATIONPRESERVED);
  656. }
  657. DrawCaptionIcon(hdc, lprc, pcursor, hbrFill, flags);
  658. /*
  659. * Restore the DC to its previous layout state.
  660. */
  661. if (dwLayout & LAYOUT_RTL) {
  662. GreSetLayout(hdc, -1, dwLayout);
  663. }
  664. } else {
  665. lprc->left += lprc->bottom - lprc->top;
  666. }
  667. }
  668. if (flags & DC_TEXT) {
  669. int cch;
  670. HFONT hfnOld;
  671. int yCentered;
  672. WCHAR szText[CCHTITLEMAX];
  673. UNICODE_STRING strTmp;
  674. PTHREADINFO ptiCurrent = PtiCurrentShared();
  675. /*
  676. * Get the text for the caption.
  677. */
  678. if (pstrText == NULL) {
  679. if (pwnd == NULL || (flags & DC_NOSENDMSG)) {
  680. if (pwnd && pwnd->strName.Length) {
  681. cch = TextCopy(&pwnd->strName, szText, CCHTITLEMAX - 1);
  682. strTmp.Length = (USHORT)(cch * sizeof(WCHAR));
  683. } else {
  684. szText[0] = TEXT('\0');
  685. cch = strTmp.Length = 0;
  686. }
  687. } else {
  688. cch = xxxGetWindowText(pwnd, szText, CCHTITLEMAX - 1);
  689. strTmp.Length = (USHORT)(cch * sizeof(WCHAR));
  690. }
  691. /*
  692. * We don't use RtlInitUnicodeString() to initialize the string
  693. * because it does a wstrlen() on the string, which is a waste
  694. * since we already know its length.
  695. */
  696. strTmp.Buffer = szText;
  697. strTmp.MaximumLength = strTmp.Length + sizeof(UNICODE_NULL);
  698. pstrText = &strTmp;
  699. } else {
  700. cch = pstrText->Length / sizeof(WCHAR);
  701. UserAssert(pstrText->Length < pstrText->MaximumLength);
  702. UserAssert(pstrText->Buffer[cch] == 0);
  703. }
  704. /*
  705. * We need to set up the font first, in case we're centering
  706. * the caption. Fortunately, no text at all is uncommon.
  707. */
  708. if (hFont == NULL) {
  709. if (flags & DC_SMALLCAP) {
  710. hFont = ghSmCaptionFont;
  711. yCentered = gcySmCaptionFontChar;
  712. } else {
  713. hFont = gpsi->hCaptionFont;
  714. yCentered = gcyCaptionFontChar;
  715. }
  716. yCentered = (lprc->top + lprc->bottom - yCentered) / 2;
  717. hfnOld = GreSelectFont(hdc, hFont);
  718. } else {
  719. TEXTMETRICW tm;
  720. /*
  721. * UNCOMMON case: only for control panel
  722. */
  723. hfnOld = GreSelectFont(hdc, hFont);
  724. if (!_GetTextMetricsW(hdc, &tm)) {
  725. RIPMSG0(RIP_WARNING, "xxxDrawCaptionTemp: _GetTextMetricsW Failed");
  726. tm.tmHeight = gpsi->tmSysFont.tmHeight;
  727. }
  728. yCentered = (lprc->top + lprc->bottom - tm.tmHeight) / 2;
  729. }
  730. /*
  731. * Draw text
  732. */
  733. if (fGradient) {
  734. FillCaptionGradient(hdc, lprc, flags & DC_ACTIVE);
  735. } else {
  736. FillRect(hdc, lprc, hbrFill);
  737. }
  738. if (hbrFill == gpsi->hbrGray) {
  739. GreSetTextColor(hdc, SYSRGB(BTNTEXT));
  740. GreSetBkColor(hdc, SYSRGB(GRAYTEXT));
  741. }
  742. /*
  743. * GDI doesn't do callbacks to the LPK. If an LPK is installed
  744. * and we're not in thread cleanup mode, call the appropriate
  745. * client side GDI routines.
  746. */
  747. if (CALL_LPK(ptiCurrent)) {
  748. xxxClientGetTextExtentPointW(hdc, pstrText->Buffer, cch, &size);
  749. } else {
  750. GreGetTextExtentW(hdc, pstrText->Buffer, cch, &size, GGTE_WIN3_EXTENT);
  751. }
  752. if (pwnd && TestWF(pwnd, WEFRTLREADING)) {
  753. oldAlign = GreSetTextAlign(hdc, TA_RTLREADING | GreGetTextAlign(hdc));
  754. }
  755. if (!(flags & DC_CENTER) && (!cch || (size.cx <= (lprc->right - lprc->left - SYSMET(CXEDGE))))) {
  756. if (pwnd && TestWF(pwnd, WEFRIGHT)) {
  757. if (CALL_LPK(ptiCurrent)) {
  758. xxxClientExtTextOutW(hdc, lprc->right - (size.cx + SYSMET(CXEDGE)), yCentered,
  759. ETO_CLIPPED, lprc, pstrText->Buffer, cch, NULL);
  760. }
  761. else {
  762. GreExtTextOutW(hdc, lprc->right - (size.cx + SYSMET(CXEDGE)), yCentered,
  763. ETO_CLIPPED, lprc, pstrText->Buffer, cch, NULL);
  764. }
  765. } else {
  766. if (CALL_LPK(ptiCurrent)) {
  767. xxxClientExtTextOutW(hdc, lprc->left + SYSMET(CXEDGE), yCentered,
  768. ETO_CLIPPED, lprc, pstrText->Buffer, cch, NULL);
  769. }
  770. else {
  771. GreExtTextOutW(hdc, lprc->left + SYSMET(CXEDGE), yCentered,
  772. ETO_CLIPPED, lprc, pstrText->Buffer, cch, NULL);
  773. }
  774. }
  775. #ifdef LAME_BUTTON
  776. if ((flags & DC_LAMEBUTTON) && pwnd != NULL && TestWF(pwnd, WEFLAMEBUTTON)) {
  777. GreSelectFont(hdc, ghLameFont);
  778. /*
  779. * Make sure the Lame! text fits in the caption
  780. */
  781. if (size.cx + gpsi->ncxLame + 2 * SYSMET(CXEDGE) <=
  782. (lprc->right - lprc->left - SYSMET(CXEDGE))) {
  783. int x;
  784. if (pwnd && TestWF(pwnd, WEFRIGHT)) {
  785. x = lprc->left + SYSMET(CXEDGE);
  786. } else {
  787. x = lprc->right - SYSMET(CXEDGE) - gpsi->ncxLame;
  788. }
  789. if (CALL_LPK(ptiCurrent)) {
  790. xxxClientExtTextOutW(hdc,
  791. x,
  792. yCentered,
  793. ETO_CLIPPED,
  794. lprc,
  795. gpsi->gwszLame,
  796. wcslen(gpsi->gwszLame),
  797. NULL);
  798. } else {
  799. GreExtTextOutW(hdc,
  800. x,
  801. yCentered,
  802. ETO_CLIPPED,
  803. lprc,
  804. gpsi->gwszLame,
  805. wcslen(gpsi->gwszLame),
  806. NULL);
  807. }
  808. }
  809. }
  810. #endif
  811. } else {
  812. DRAWTEXTPARAMS dtp;
  813. UINT wSide;
  814. dtp.cbSize = sizeof(DRAWTEXTPARAMS);
  815. dtp.iLeftMargin = SYSMET(CXEDGE);
  816. dtp.iRightMargin = 0;
  817. wSide = (flags & DC_CENTER) ? DT_CENTER
  818. : ((pwnd && TestWF(pwnd, WEFRIGHT)) ? DT_RIGHT : 0);
  819. DrawTextEx(hdc,
  820. pstrText->Buffer,
  821. cch,
  822. lprc,
  823. DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER |
  824. wSide, &dtp);
  825. fItFit = FALSE;
  826. }
  827. if (pwnd && TestWF(pwnd, WEFRTLREADING)) {
  828. GreSetTextAlign(hdc, oldAlign);
  829. }
  830. if (hfnOld) {
  831. GreSelectFont(hdc, hfnOld);
  832. }
  833. }
  834. /*
  835. * Restore colors.
  836. */
  837. GreSetTextColor(hdc, clrOldText);
  838. GreSetBkColor(hdc, clrOldBk);
  839. if (hbrFill == gpsi->hbrGray) {
  840. GreSetBkMode(hdc, iOldMode);
  841. }
  842. return fItFit;
  843. }
  844. /***************************************************************************\
  845. * xxxDrawCaptionBar
  846. *
  847. *
  848. \***************************************************************************/
  849. VOID xxxDrawCaptionBar(
  850. PWND pwnd,
  851. HDC hdc,
  852. UINT wFlags)
  853. {
  854. UINT bm = OBI_CLOSE;
  855. RECT rcWindow;
  856. HBRUSH hBrush = NULL;
  857. HBRUSH hCapBrush;
  858. int colorBorder;
  859. UINT wBtns;
  860. UINT wCode;
  861. BOOL fGradient = FALSE;
  862. CheckLock(pwnd);
  863. /*
  864. * If we're not currently showing on the screen, return.
  865. * NOTE
  866. * If you remove the IsVisible() check from DrawWindowFrame(), then
  867. * be careful to remove the NC_NOVISIBLE flag too. This is a smallish
  868. * speed thing, so that we don't have to call IsVisible() twice on a
  869. * window. DrawWindowFrame() already checks.
  870. */
  871. if (!(wFlags & DC_NOVISIBLE) && !IsVisible(pwnd)) {
  872. return;
  873. }
  874. /*
  875. * Clear this flag so we know the frame has been drawn.
  876. */
  877. ClearHungFlag(pwnd, WFREDRAWFRAMEIFHUNG);
  878. GetRect(pwnd, &rcWindow, GRECT_WINDOW | GRECT_WINDOWCOORDS);
  879. /*
  880. * The TestALPHA() will return false in ts connections because the
  881. * gbDisableAlpha flag will be set to true. So, we need to special case
  882. * for TS connections. If this is a remote connection and the gradient
  883. * captions flag is set, ideally, we should force it to draw gradients.
  884. * However, for 8-bit color, enabling gradients looks ugly. We will fix
  885. * this for Blackcomb.
  886. *
  887. * The code should be something like this:
  888. * fGradient = IsRemoteConnection() && !8-bit color ? TestEffectUP(GRADIENTCAPTIONS) : TestALPHA(GRADIENTCAPTIONS);
  889. */
  890. fGradient = TestALPHA(GRADIENTCAPTIONS);
  891. if (fGradient) {
  892. hCapBrush = (wFlags & DC_ACTIVE) ? SYSHBR(GRADIENTACTIVECAPTION) : SYSHBR(GRADIENTINACTIVECAPTION);
  893. } else {
  894. hCapBrush = (wFlags & DC_ACTIVE) ? SYSHBR(ACTIVECAPTION) : SYSHBR(INACTIVECAPTION);
  895. }
  896. wCode = 0;
  897. if (!xxxMNCanClose(pwnd)) {
  898. wCode |= NOCLOSE;
  899. }
  900. if (!TestWF(pwnd, WFMAXBOX)) {
  901. wCode |= NOMAX;
  902. } else if (TestWF(pwnd, WFMAXIMIZED)) {
  903. wCode |= MAX;
  904. }
  905. if (!TestWF(pwnd, WFMINBOX)) {
  906. wCode |= NOMIN;
  907. } else if (TestWF(pwnd, WFMINIMIZED)) {
  908. wCode |= MIN;
  909. }
  910. if (TestWF(pwnd, WFMINIMIZED)) {
  911. if (wFlags & DC_FRAME) {
  912. /*
  913. * Raised outer edge + border
  914. */
  915. DrawEdge(hdc, &rcWindow, EDGE_RAISED, (BF_RECT | BF_ADJUST));
  916. DrawFrame(hdc, &rcWindow, 1, DF_3DFACE);
  917. InflateRect(&rcWindow, -SYSMET(CXBORDER), -SYSMET(CYBORDER));
  918. } else {
  919. InflateRect(&rcWindow, -SYSMET(CXFIXEDFRAME), -SYSMET(CYFIXEDFRAME));
  920. }
  921. rcWindow.bottom = rcWindow.top + SYSMET(CYSIZE);
  922. hBrush = GreSelectBrush(hdc, hCapBrush);
  923. } else {
  924. /*
  925. * BOGUS
  926. * What color should we draw borders in? The check is NOT simple.
  927. * At create time, we set the 3D bits. NCCREATE will also
  928. * set them for listboxes, edit fields,e tc.
  929. */
  930. colorBorder = (TestWF(pwnd, WEFEDGEMASK) && !TestWF(pwnd, WFOLDUI)) ? COLOR_3DFACE : COLOR_WINDOWFRAME;
  931. /*
  932. * Draw the window frame.
  933. */
  934. if (wFlags & DC_FRAME) {
  935. /*
  936. * Window edge
  937. */
  938. if (TestWF(pwnd, WEFWINDOWEDGE)) {
  939. DrawEdge(hdc, &rcWindow, EDGE_RAISED, BF_RECT | BF_ADJUST);
  940. } else if (TestWF(pwnd, WEFSTATICEDGE)) {
  941. DrawEdge(hdc, &rcWindow, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
  942. }
  943. /*
  944. * Size border
  945. */
  946. if (TestWF(pwnd, WFSIZEBOX)) {
  947. DrawFrame(hdc,
  948. &rcWindow,
  949. gpsi->gclBorder,
  950. ((wFlags & DC_ACTIVE) ? DF_ACTIVEBORDER : DF_INACTIVEBORDER));
  951. InflateRect(&rcWindow,
  952. -gpsi->gclBorder * SYSMET(CXBORDER),
  953. -gpsi->gclBorder * SYSMET(CYBORDER));
  954. }
  955. /*
  956. * Normal border
  957. */
  958. if (TestWF(pwnd, WFBORDERMASK) || TestWF(pwnd, WEFDLGMODALFRAME)) {
  959. DrawFrame(hdc, &rcWindow, 1, (colorBorder << 3));
  960. InflateRect(&rcWindow, -SYSMET(CXBORDER), -SYSMET(CYBORDER));
  961. }
  962. } else {
  963. int cBorders;
  964. cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE);
  965. InflateRect(&rcWindow,
  966. -cBorders * SYSMET(CXBORDER),
  967. -cBorders * SYSMET(CYBORDER));
  968. }
  969. /*
  970. * Punt if the window doesn't have a caption currently showing on
  971. * screen.
  972. */
  973. if (!TestWF(pwnd, WFCPRESENT)) {
  974. return;
  975. }
  976. if (TestWF(pwnd, WEFTOOLWINDOW)) {
  977. wCode |= SMCAP;
  978. rcWindow.bottom = rcWindow.top + SYSMET(CYSMSIZE);
  979. bm = OBI_CLOSE_PAL;
  980. } else {
  981. rcWindow.bottom = rcWindow.top + SYSMET(CYSIZE);
  982. }
  983. {
  984. POLYPATBLT PolyData;
  985. PolyData.x = rcWindow.left;
  986. PolyData.y = rcWindow.bottom;
  987. PolyData.cx = rcWindow.right - rcWindow.left;
  988. PolyData.cy = SYSMET(CYBORDER);
  989. PolyData.BrClr.hbr = SYSHBRUSH(colorBorder);
  990. GrePolyPatBlt(hdc,PATCOPY,&PolyData,1,PPB_BRUSH);
  991. }
  992. GreSelectBrush(hdc, hCapBrush);
  993. }
  994. if (!TestWF(pwnd, WFSYSMENU) && TestWF(pwnd, WFWIN40COMPAT)) {
  995. goto JustDrawIt;
  996. }
  997. /*
  998. * New Rules:
  999. * (1) The caption has a horz border beneath it separating it from the
  1000. * menu or client.
  1001. * (2) The caption text area has an edge of space on the left and right
  1002. * before the characters.
  1003. * (3) We account for the descent below the baseline of the caption char
  1004. */
  1005. wBtns = 1;
  1006. if (!(wFlags & DC_BUTTONS)) {
  1007. if ((!wCode) || (!(wCode & SMCAP) && ((wCode & NOSIZE) != NOSIZE))) {
  1008. wBtns += 2;
  1009. } else {
  1010. rcWindow.right -= SYSMET(CXEDGE);
  1011. if ((wCode == NOSIZE) && (wCode && TestWF(pwnd, WEFCONTEXTHELP))) {
  1012. wBtns++;
  1013. }
  1014. }
  1015. rcWindow.right -= wBtns * ((wCode & SMCAP) ? SYSMET(CXSMSIZE) : SYSMET(CXSIZE));
  1016. goto JustDrawIt;
  1017. }
  1018. if (!wCode || (wCode == NOSIZE)) {
  1019. POEMBITMAPINFO pOem = gpsi->oembmi + OBI_CAPBTNS;
  1020. int cx;
  1021. cx = (wCode ? SYSMET(CXSIZE) + SYSMET(CXEDGE) : SYSMET(CXSIZE) * 3);
  1022. if (!(wFlags & DC_ACTIVE))
  1023. pOem += DOBI_CAPOFF;
  1024. rcWindow.right -= cx;
  1025. GreBitBlt(hdc,
  1026. rcWindow.right,
  1027. rcWindow.top,
  1028. cx,
  1029. pOem->cy,
  1030. HDCBITS(),
  1031. pOem->x + pOem->cx - SYSMET(CXSIZE) - cx,
  1032. pOem->y,
  1033. SRCCOPY,
  1034. 0);
  1035. if (wCode && TestWF(pwnd, WEFCONTEXTHELP)) {
  1036. rcWindow.right -= SYSMET(CXSIZE) - SYSMET(CXEDGE);
  1037. GreBitBlt(hdc,
  1038. rcWindow.right,
  1039. rcWindow.top,
  1040. SYSMET(CXSIZE),
  1041. pOem->cy,
  1042. HDCBITS(),
  1043. pOem->x + pOem->cx - SYSMET(CXSIZE),
  1044. pOem->y,
  1045. SRCCOPY,
  1046. 0);
  1047. /*
  1048. * If the UI language is Hebrew we do not want to mirror the ? mark only
  1049. * Then redraw ? with out the button frame.
  1050. */
  1051. if (HEBREW_UI_LANGID() && TestWF(pwnd, WEFLAYOUTRTL)) {
  1052. GreBitBlt(hdc,
  1053. rcWindow.right-SYSMET(CXEDGE),
  1054. rcWindow.top+2,
  1055. SYSMET(CXSIZE)-SYSMET(CXEDGE)*2,
  1056. pOem->cy-4,
  1057. HDCBITS(),
  1058. pOem->x + pOem->cx - SYSMET(CXSIZE) + SYSMET(CXEDGE),
  1059. pOem->y + SYSMET(CXEDGE),
  1060. SRCCOPY|NOMIRRORBITMAP,
  1061. 0);
  1062. }
  1063. }
  1064. goto JustDrawIt;
  1065. }
  1066. /*
  1067. * Draw the caption buttons
  1068. */
  1069. rcWindow.top += SYSMET(CYEDGE);
  1070. rcWindow.bottom -= SYSMET(CYEDGE);
  1071. rcWindow.right -= SYSMET(CXEDGE);
  1072. GrePatBlt(hdc,
  1073. rcWindow.right,
  1074. rcWindow.top,
  1075. SYSMET(CXEDGE),
  1076. rcWindow.bottom - rcWindow.top,
  1077. PATCOPY);
  1078. if (wCode & NOCLOSE) {
  1079. bm += DOBI_INACTIVE;
  1080. }
  1081. rcWindow.right -= gpsi->oembmi[bm].cx;
  1082. BitBltSysBmp(hdc, rcWindow.right, rcWindow.top, bm);
  1083. if (!(wCode & SMCAP) && ((wCode & NOSIZE) != NOSIZE)) {
  1084. rcWindow.right -= SYSMET(CXEDGE);
  1085. GrePatBlt(hdc,
  1086. rcWindow.right,
  1087. rcWindow.top,
  1088. SYSMET(CXEDGE),
  1089. rcWindow.bottom - rcWindow.top,
  1090. PATCOPY);
  1091. /*
  1092. * Max Box.
  1093. *
  1094. * If window is maximized use the restore bitmap; otherwise use the
  1095. * regular zoom bitmap.
  1096. */
  1097. bm = (wCode & MAX) ? OBI_RESTORE : ((wCode & NOMAX) ? OBI_ZOOM_I : OBI_ZOOM);
  1098. rcWindow.right -= gpsi->oembmi[bm].cx;
  1099. BitBltSysBmp(hdc, rcWindow.right, rcWindow.top, bm);
  1100. /*
  1101. * Min Box.
  1102. */
  1103. bm = (wCode & MIN) ? OBI_RESTORE : ((wCode & NOMIN) ? OBI_REDUCE_I : OBI_REDUCE);
  1104. rcWindow.right -= gpsi->oembmi[bm].cx;
  1105. BitBltSysBmp(hdc, rcWindow.right, rcWindow.top, bm);
  1106. rcWindow.right -= SYSMET(CXEDGE);
  1107. GrePatBlt(hdc,
  1108. rcWindow.right,
  1109. rcWindow.top,
  1110. SYSMET(CXEDGE),
  1111. rcWindow.bottom - rcWindow.top,
  1112. PATCOPY);
  1113. wBtns += 2;
  1114. }
  1115. if ((wCode & (NOCLOSE | NOSIZE)) &&
  1116. (!(wCode & SMCAP)) && TestWF(pwnd, WEFCONTEXTHELP)) {
  1117. rcWindow.right -= SYSMET(CXEDGE);
  1118. GrePatBlt(hdc,
  1119. rcWindow.right,
  1120. rcWindow.top,
  1121. SYSMET(CXEDGE),
  1122. rcWindow.bottom - rcWindow.top,
  1123. PATCOPY);
  1124. bm = OBI_HELP;
  1125. rcWindow.right -= gpsi->oembmi[bm].cx;
  1126. BitBltSysBmp(hdc, rcWindow.right, rcWindow.top, bm);
  1127. wBtns++;
  1128. }
  1129. rcWindow.top -= SYSMET(CYEDGE);
  1130. rcWindow.bottom += SYSMET(CYEDGE);
  1131. wBtns *= (wCode & SMCAP) ? SYSMET(CXSMSIZE) : SYSMET(CXSIZE);
  1132. {
  1133. POLYPATBLT PolyData[2];
  1134. PolyData[0].x = rcWindow.right;
  1135. PolyData[0].y = rcWindow.top;
  1136. PolyData[0].cx = wBtns;
  1137. PolyData[0].cy = SYSMET(CYEDGE);
  1138. PolyData[0].BrClr.hbr = NULL;
  1139. PolyData[1].x = rcWindow.right;
  1140. PolyData[1].y = rcWindow.bottom - SYSMET(CYEDGE);
  1141. PolyData[1].cx = wBtns;
  1142. PolyData[1].cy = SYSMET(CYEDGE);
  1143. PolyData[1].BrClr.hbr = NULL;
  1144. GrePolyPatBlt(hdc,PATCOPY,&PolyData[0],2,PPB_BRUSH);
  1145. }
  1146. /*
  1147. * We're going to release this DC -- we don't need to bother reselecting
  1148. * in the old brush.
  1149. */
  1150. if (hBrush) {
  1151. GreSelectBrush(hdc, hBrush);
  1152. }
  1153. JustDrawIt:
  1154. /*
  1155. * Call DrawCaption only if we need to draw the icon or the text.
  1156. *
  1157. * If the text gets truncated, set the window flag for the caption
  1158. * tooltip.
  1159. */
  1160. if (wFlags & (DC_TEXT | DC_ICON)) {
  1161. #ifdef LAME_BUTTON
  1162. wFlags |= DC_LAMEBUTTON;
  1163. #endif // LAME_BUTTON
  1164. /*
  1165. * The TestALPHA() will return false in ts connections because the
  1166. * gbDisableAlpha flag will be set to true. So, we need to special
  1167. * case for TS connections. If this is a remote connection and the
  1168. * gradient captions flag is set, ideally, we should force it to
  1169. * draw gradients. However, for 8-bit color, enabling gradients
  1170. * looks ugly. We will fix this for Blackcomb.
  1171. */
  1172. if (!xxxDrawCaptionTemp(pwnd,
  1173. hdc,
  1174. &rcWindow,
  1175. NULL,
  1176. NULL,
  1177. NULL,
  1178. wFlags | ((wCode & SMCAP) ? DC_SMALLCAP : 0) |
  1179. (fGradient? DC_GRADIENT : 0))) {
  1180. SetWF(pwnd, WEFTRUNCATEDCAPTION);
  1181. } else {
  1182. ClrWF(pwnd, WEFTRUNCATEDCAPTION);
  1183. }
  1184. }
  1185. }