Source code of Windows XP (NT5)
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.

3190 lines
86 KiB

  1. /*
  2. ** CUTILS.C
  3. **
  4. ** Common utilities for common controls
  5. **
  6. */
  7. #include "ctlspriv.h"
  8. #include "advpub.h" // For REGINSTALL
  9. #include <ntverp.h>
  10. #include "ccver.h" // App compat version hacks
  11. #include <shfusion.h>
  12. #ifndef SSW_EX_IGNORESETTINGS
  13. #define SSW_EX_IGNORESETTINGS 0x00040000 // ignore system settings to turn on/off smooth scroll
  14. #endif
  15. // the insert mark is 6 pixels wide
  16. #define INSERTMARKSIZE 6
  17. //
  18. // Globals - REVIEW_32
  19. //
  20. BOOL g_fAnimate;
  21. BOOL g_fSmoothScroll;
  22. BOOL g_fEnableBalloonTips = TRUE;
  23. int g_cxEdge;
  24. int g_cyEdge;
  25. int g_cxEdgeScaled;
  26. int g_cyEdgeScaled;
  27. int g_cxBorder;
  28. int g_cyBorder;
  29. int g_cxScreen;
  30. int g_cyScreen;
  31. int g_cxFrame;
  32. int g_cyFrame;
  33. int g_cxVScroll;
  34. int g_cyHScroll;
  35. int g_cxIcon, g_cyIcon;
  36. int g_cxSmIcon, g_cySmIcon;
  37. int g_cxIconSpacing, g_cyIconSpacing;
  38. int g_cxIconMargin, g_cyIconMargin;
  39. int g_cyLabelSpace;
  40. int g_cxLabelMargin;
  41. int g_cxDoubleClk;
  42. int g_cyDoubleClk;
  43. int g_cxScrollbar;
  44. int g_cyScrollbar;
  45. int g_fDragFullWindows;
  46. double g_dScaleX = 1.0;
  47. double g_dScaleY = 1.0;
  48. BOOL g_fScale = FALSE;
  49. int g_iDPI = 96.0;
  50. BOOL g_fHighContrast = FALSE;
  51. int g_cyCompensateInternalLeading;
  52. int g_fLeftAligned = FALSE;
  53. COLORREF g_clrWindow;
  54. COLORREF g_clrWindowText;
  55. COLORREF g_clrWindowFrame;
  56. COLORREF g_clrGrayText;
  57. COLORREF g_clrBtnText;
  58. COLORREF g_clrBtnFace;
  59. COLORREF g_clrBtnShadow;
  60. COLORREF g_clrBtnHighlight;
  61. COLORREF g_clrHighlight;
  62. COLORREF g_clrHighlightText;
  63. COLORREF g_clrInfoText;
  64. COLORREF g_clrInfoBk;
  65. COLORREF g_clr3DDkShadow;
  66. COLORREF g_clr3DLight;
  67. COLORREF g_clrMenuHilight;
  68. COLORREF g_clrMenuText;
  69. HBRUSH g_hbrGrayText;
  70. HBRUSH g_hbrWindow;
  71. HBRUSH g_hbrWindowText;
  72. HBRUSH g_hbrWindowFrame;
  73. HBRUSH g_hbrBtnFace;
  74. HBRUSH g_hbrBtnHighlight;
  75. HBRUSH g_hbrBtnShadow;
  76. HBRUSH g_hbrHighlight;
  77. HBRUSH g_hbrMenuHilight;
  78. HBRUSH g_hbrMenuText;
  79. DWORD g_dwHoverSelectTimeout;
  80. HFONT g_hfontSystem;
  81. void InitGlobalColors()
  82. {
  83. BOOL fFlatMenuMode = FALSE;
  84. static fMenuColorAlloc = FALSE;
  85. g_clrWindow = GetSysColor(COLOR_WINDOW);
  86. g_clrWindowText = GetSysColor(COLOR_WINDOWTEXT);
  87. g_clrWindowFrame = GetSysColor(COLOR_WINDOWFRAME);
  88. g_clrGrayText = GetSysColor(COLOR_GRAYTEXT);
  89. g_clrBtnText = GetSysColor(COLOR_BTNTEXT);
  90. g_clrBtnFace = GetSysColor(COLOR_BTNFACE);
  91. g_clrBtnShadow = GetSysColor(COLOR_BTNSHADOW);
  92. g_clrBtnHighlight = GetSysColor(COLOR_BTNHIGHLIGHT);
  93. g_clrHighlight = GetSysColor(COLOR_HIGHLIGHT);
  94. g_clrHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  95. g_clrInfoText = GetSysColor(COLOR_INFOTEXT);
  96. g_clrInfoBk = GetSysColor(COLOR_INFOBK);
  97. g_clr3DDkShadow = GetSysColor(COLOR_3DDKSHADOW);
  98. g_clr3DLight = GetSysColor(COLOR_3DLIGHT);
  99. SystemParametersInfo(SPI_GETFLATMENU, 0, (PVOID)&fFlatMenuMode, 0);
  100. if (fFlatMenuMode)
  101. {
  102. g_clrMenuHilight = GetSysColor(COLOR_MENUHILIGHT);
  103. g_clrMenuText = GetSysColor(COLOR_MENUTEXT);
  104. }
  105. else
  106. {
  107. g_clrMenuHilight = GetBorderSelectColor(60, GetSysColor(COLOR_HIGHLIGHT));
  108. g_clrMenuText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  109. }
  110. g_hbrGrayText = GetSysColorBrush(COLOR_GRAYTEXT);
  111. g_hbrWindow = GetSysColorBrush(COLOR_WINDOW);
  112. g_hbrWindowText = GetSysColorBrush(COLOR_WINDOWTEXT);
  113. g_hbrWindowFrame = GetSysColorBrush(COLOR_WINDOWFRAME);
  114. g_hbrBtnFace = GetSysColorBrush(COLOR_BTNFACE);
  115. g_hbrBtnHighlight = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
  116. g_hbrBtnShadow = GetSysColorBrush(COLOR_BTNSHADOW);
  117. g_hbrHighlight = GetSysColorBrush(COLOR_HIGHLIGHT);
  118. g_hfontSystem = GetStockObject(SYSTEM_FONT);
  119. if (fMenuColorAlloc)
  120. {
  121. DeleteObject(g_hbrMenuHilight);
  122. }
  123. if (fFlatMenuMode)
  124. {
  125. fMenuColorAlloc = FALSE;
  126. g_hbrMenuHilight = GetSysColorBrush(COLOR_MENUHILIGHT);
  127. g_hbrMenuText = GetSysColorBrush(COLOR_MENUTEXT);
  128. }
  129. else
  130. {
  131. fMenuColorAlloc = TRUE;
  132. g_hbrMenuHilight = CreateSolidBrush(g_clrMenuHilight);
  133. g_hbrMenuText = GetSysColorBrush(COLOR_HIGHLIGHTTEXT);
  134. }
  135. }
  136. #define CCS_ALIGN (CCS_TOP | CCS_NOMOVEY | CCS_BOTTOM)
  137. ///
  138. //
  139. // Implement MapWindowPoints as if the hwndFrom and hwndTo aren't
  140. // mirrored. This is used when any of the windows (hwndFrom or hwndTo)
  141. // are mirrored. See below. [samera]
  142. //
  143. int TrueMapWindowPoints(HWND hwndFrom, HWND hwndTo, LPPOINT lppt, UINT cPoints)
  144. {
  145. int dx, dy;
  146. RECT rcFrom={0,0,0,0}, rcTo={0,0,0,0};
  147. if (hwndFrom) {
  148. GetClientRect(hwndFrom, &rcFrom);
  149. MapWindowPoints(hwndFrom, NULL, (LPPOINT)&rcFrom.left, 2);
  150. }
  151. if (hwndTo) {
  152. GetClientRect(hwndTo, &rcTo);
  153. MapWindowPoints(hwndTo, NULL, (LPPOINT)&rcTo.left, 2);
  154. }
  155. dx = rcFrom.left - rcTo.left;
  156. dy = rcFrom.top - rcTo.top;
  157. /*
  158. * Map the points
  159. */
  160. while (cPoints--) {
  161. lppt->x += dx;
  162. lppt->y += dy;
  163. ++lppt;
  164. }
  165. return MAKELONG(dx, dy);
  166. }
  167. // Note that the default alignment is CCS_BOTTOM
  168. //
  169. void NewSize(HWND hWnd, int nThickness, LONG style, int left, int top, int width, int height)
  170. {
  171. // Resize the window unless the user said not to
  172. //
  173. if (!(style & CCS_NORESIZE))
  174. {
  175. RECT rc, rcWindow, rcBorder;
  176. // Remember size that was passed in and don't bother calling SetWindowPos if we're not
  177. // actually going to change the window size
  178. int leftSave = left;
  179. int topSave = top;
  180. int widthSave = width;
  181. int heightSave = height;
  182. // Calculate the borders around the client area of the status bar
  183. GetWindowRect(hWnd, &rcWindow);
  184. rcWindow.right -= rcWindow.left; // -> dx
  185. rcWindow.bottom -= rcWindow.top; // -> dy
  186. GetClientRect(hWnd, &rc);
  187. //
  188. // If the window is mirrored, mirror the anchor point
  189. // since it will be passed to SWP which accepts screen
  190. // ccordinates. This mainly fixes the display of status bar
  191. // and others. [samera]
  192. //
  193. if (IS_WINDOW_RTL_MIRRORED(hWnd))
  194. {
  195. TrueMapWindowPoints(hWnd, NULL, (LPPOINT)&rc.left, 1);
  196. }
  197. else
  198. {
  199. ClientToScreen(hWnd, (LPPOINT)&rc);
  200. }
  201. rcBorder.left = rc.left - rcWindow.left;
  202. rcBorder.top = rc.top - rcWindow.top ;
  203. rcBorder.right = rcWindow.right - rc.right - rcBorder.left;
  204. rcBorder.bottom = rcWindow.bottom - rc.bottom - rcBorder.top ;
  205. if (style & CCS_VERT)
  206. nThickness += rcBorder.left + rcBorder.right;
  207. else
  208. nThickness += rcBorder.top + rcBorder.bottom;
  209. // Check whether to align to the parent window
  210. //
  211. if (style & CCS_NOPARENTALIGN)
  212. {
  213. // Check out whether this bar is top aligned or bottom aligned
  214. //
  215. switch (style & CCS_ALIGN)
  216. {
  217. case CCS_TOP:
  218. case CCS_NOMOVEY:
  219. break;
  220. default: // CCS_BOTTOM
  221. if(style & CCS_VERT)
  222. left = left + width - nThickness;
  223. else
  224. top = top + height - nThickness;
  225. }
  226. }
  227. else
  228. {
  229. // It is assumed there is a parent by default
  230. //
  231. GetClientRect(GetParent(hWnd), &rc);
  232. // Don't forget to account for the borders
  233. //
  234. if(style & CCS_VERT)
  235. {
  236. top = -rcBorder.right;
  237. height = rc.bottom + rcBorder.top + rcBorder.bottom;
  238. }
  239. else
  240. {
  241. left = -rcBorder.left;
  242. width = rc.right + rcBorder.left + rcBorder.right;
  243. }
  244. if ((style & CCS_ALIGN) == CCS_TOP)
  245. {
  246. if(style & CCS_VERT)
  247. left = -rcBorder.left;
  248. else
  249. top = -rcBorder.top;
  250. }
  251. else if ((style & CCS_ALIGN) != CCS_NOMOVEY)
  252. {
  253. if (style & CCS_VERT)
  254. left = rc.right - nThickness + rcBorder.right;
  255. else
  256. top = rc.bottom - nThickness + rcBorder.bottom;
  257. }
  258. }
  259. if (!(style & CCS_NOMOVEY) && !(style & CCS_NODIVIDER))
  260. {
  261. if (style & CCS_VERT)
  262. left += g_cxEdge;
  263. else
  264. top += g_cyEdge; // double pixel edge thing
  265. }
  266. if(style & CCS_VERT)
  267. width = nThickness;
  268. else
  269. height = nThickness;
  270. SetWindowPos(hWnd, NULL, left, top, width, height, SWP_NOZORDER);
  271. }
  272. }
  273. BOOL MGetTextExtent(HDC hdc, LPCTSTR lpstr, int cnt, int * pcx, int * pcy)
  274. {
  275. BOOL fSuccess;
  276. SIZE size = {0,0};
  277. if (cnt == -1)
  278. cnt = lstrlen(lpstr);
  279. fSuccess=GetTextExtentPoint(hdc, lpstr, cnt, &size);
  280. if (pcx)
  281. *pcx=size.cx;
  282. if (pcy)
  283. *pcy=size.cy;
  284. return fSuccess;
  285. }
  286. // these are the default colors used to map the dib colors
  287. // to the current system colors
  288. #define RGB_BUTTONTEXT (RGB(000,000,000)) // black
  289. #define RGB_BUTTONSHADOW (RGB(128,128,128)) // dark grey
  290. #define RGB_BUTTONFACE (RGB(192,192,192)) // bright grey
  291. #define RGB_BUTTONHILIGHT (RGB(255,255,255)) // white
  292. #define RGB_BACKGROUNDSEL (RGB(000,000,255)) // blue
  293. #define RGB_BACKGROUND (RGB(255,000,255)) // magenta
  294. #ifdef UNIX
  295. RGBQUAD CLR_TO_RGBQUAD( COLORREF clr)
  296. {
  297. /* main modif for unix: keep the extra byte in the rgbReserved field
  298. This is used for our motif colors that are expressed in term of
  299. CMAPINDEX rather than real RGBs, this function is also portable
  300. and immune to endianness*/
  301. RGBQUAD rgbqResult;
  302. rgbqResult.rgbRed=GetRValue(clr);
  303. rgbqResult.rgbGreen=GetGValue(clr);
  304. rgbqResult.rgbBlue=GetBValue(clr);
  305. rgbqResult.rgbReserved=(BYTE)((clr>>24)&0xff);
  306. return rgbqResult;
  307. }
  308. COLORREF RGBQUAD_TO_CLR( RGBQUAD rgbQ )
  309. {
  310. return ( ((DWORD)rgbQ.rgbRed) | ((DWORD)(rgbQ.rgbGreen << 8)) |
  311. ((DWORD)(rgbQ.rgbBlue << 16)) | ((DWORD)(rgbQ.rgbReserved << 24)) );
  312. }
  313. /* This is just plain wrong
  314. 1) they definition of COLORMAP is based on COLORREFs but a
  315. DIB color map is RGBQUAD
  316. 2) FlipColor as per previous definition does not flip at all
  317. since it goes from COLORREF to COLORREF
  318. so we are better doing nothing, so we dont loose our CMAP flag
  319. (Jose)
  320. */
  321. #define FlipColor(rgb) (rgb)
  322. #else
  323. #define FlipColor(rgb) (RGB(GetBValue(rgb), GetGValue(rgb), GetRValue(rgb)))
  324. #endif /* UNIX */
  325. #define MAX_COLOR_MAPS 16
  326. void _MapBitmapColors(LPBITMAPINFOHEADER pbih, LPCOLORMAP pcmp, int iCmps, COLOR_STRUCT* pcsMask, UINT cMask, DWORD wFlags)
  327. {
  328. static const COLORMAP c_acmpSys[] =
  329. {
  330. { RGB_BUTTONTEXT, COLOR_BTNTEXT }, // black
  331. { RGB_BUTTONSHADOW, COLOR_BTNSHADOW }, // dark grey
  332. { RGB_BUTTONFACE, COLOR_BTNFACE }, // bright grey
  333. { RGB_BUTTONHILIGHT, COLOR_BTNHIGHLIGHT }, // white
  334. { RGB_BACKGROUNDSEL, COLOR_HIGHLIGHT }, // blue
  335. { RGB_BACKGROUND, COLOR_WINDOW }, // magenta
  336. };
  337. COLORMAP acmpDef[ARRAYSIZE(c_acmpSys)];
  338. COLORMAP acmpDIB[MAX_COLOR_MAPS];
  339. COLOR_STRUCT* pcs = (COLOR_STRUCT*)(((LPBYTE)pbih) + pbih->biSize);
  340. int i;
  341. if (!pcmp)
  342. {
  343. // Get system colors for the default color map
  344. for (i = 0; i < ARRAYSIZE(acmpDef); i++)
  345. {
  346. acmpDef[i].from = c_acmpSys[i].from;
  347. acmpDef[i].to = GetSysColor((int)c_acmpSys[i].to);
  348. }
  349. pcmp = acmpDef;
  350. iCmps = ARRAYSIZE(acmpDef);
  351. }
  352. else
  353. {
  354. // Sanity check color map count
  355. if (iCmps > MAX_COLOR_MAPS)
  356. iCmps = MAX_COLOR_MAPS;
  357. }
  358. for (i = 0; i < iCmps; i++)
  359. {
  360. acmpDIB[i].to = FlipColor(pcmp[i].to);
  361. acmpDIB[i].from = FlipColor(pcmp[i].from);
  362. }
  363. // if we are creating a mask, build a color table with white
  364. // marking the transparent section (where it used to be background)
  365. // and black marking the opaque section (everything else). this
  366. // table is used below to build the mask using the original DIB bits.
  367. if (wFlags & CMB_MASKED)
  368. {
  369. COLOR_STRUCT csBkgnd = FlipColor(RGB_BACKGROUND);
  370. ASSERT(cMask == MAX_COLOR_MAPS);
  371. for (i = 0; i < MAX_COLOR_MAPS; i++)
  372. {
  373. if (pcs[i] == csBkgnd)
  374. pcsMask[i] = 0xFFFFFF; // transparent section
  375. else
  376. pcsMask[i] = 0x000000; // opaque section
  377. }
  378. }
  379. for (i = 0; i < MAX_COLOR_MAPS; i++)
  380. {
  381. int j;
  382. for (j = 0; j < iCmps; j++)
  383. {
  384. if ((pcs[i] & 0x00FFFFFF) == acmpDIB[j].from)
  385. {
  386. pcs[i] = acmpDIB[j].to;
  387. break;
  388. }
  389. }
  390. }
  391. }
  392. HBITMAP _CreateMappedBitmap(LPBITMAPINFOHEADER pbih, LPBYTE lpBits, COLOR_STRUCT* pcsMask, UINT cMask, UINT wFlags)
  393. {
  394. HBITMAP hbm = NULL;
  395. HDC hdc = GetDC(NULL);
  396. if (hdc)
  397. {
  398. HDC hdcMem = CreateCompatibleDC(hdc);
  399. if (hdcMem)
  400. {
  401. int nWidth = (int)pbih->biWidth;
  402. int nHeight = (int)pbih->biHeight;
  403. if (wFlags & CMB_DIBSECTION)
  404. {
  405. // Have to edit the header slightly, since CreateDIBSection supports
  406. // only BI_RGB and BI_BITFIELDS. This is the same whackery that USER
  407. // does in LoadImage.
  408. LPVOID pvDummy;
  409. DWORD dwCompression = pbih->biCompression;
  410. if (dwCompression != BI_BITFIELDS)
  411. pbih->biCompression = BI_RGB;
  412. hbm = CreateDIBSection(hdc, (LPBITMAPINFO)pbih, DIB_RGB_COLORS,
  413. &pvDummy, NULL, 0);
  414. pbih->biCompression = dwCompression;
  415. }
  416. if (hbm == NULL)
  417. {
  418. // If CMB_DIBSECTION failed, then create a DDB instead. Not perfect,
  419. // but better than creating nothing. We also get here if the caller
  420. // didn't ask for a DIB section.
  421. // if creating a mask, the bitmap needs to be twice as wide.
  422. int nWidthBmp;
  423. if (wFlags & CMB_MASKED)
  424. nWidthBmp = nWidth * 2;
  425. else
  426. nWidthBmp = nWidth;
  427. hbm = CreateCompatibleBitmap(hdc, nWidthBmp, nHeight);
  428. }
  429. if (hbm)
  430. {
  431. HBITMAP hbmOld = SelectObject(hdcMem, hbm);
  432. // set the main image
  433. StretchDIBits(hdcMem, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight, lpBits,
  434. (LPBITMAPINFO)pbih, DIB_RGB_COLORS, SRCCOPY);
  435. // if building a mask, replace the DIB's color table with the
  436. // mask's black/white table and set the bits. in order to
  437. // complete the masked effect, the actual image needs to be
  438. // modified so that it has the color black in all sections
  439. // that are to be transparent.
  440. if (wFlags & CMB_MASKED)
  441. {
  442. if (cMask > 0)
  443. {
  444. COLOR_STRUCT* pcs = (COLOR_STRUCT*)(((LPBYTE)pbih) + pbih->biSize);
  445. hmemcpy(pcs, pcsMask, cMask * sizeof(RGBQUAD));
  446. }
  447. StretchDIBits(hdcMem, nWidth, 0, nWidth, nHeight, 0, 0, nWidth, nHeight, lpBits,
  448. (LPBITMAPINFO)pbih, DIB_RGB_COLORS, SRCCOPY);
  449. BitBlt(hdcMem, 0, 0, nWidth, nHeight, hdcMem, nWidth, 0, 0x00220326); // DSna
  450. }
  451. SelectObject(hdcMem, hbmOld);
  452. }
  453. DeleteObject(hdcMem);
  454. }
  455. ReleaseDC(NULL, hdc);
  456. }
  457. return hbm;
  458. }
  459. // This is almost the same as LoadImage(..., LR_MAP3DCOLORS) except that
  460. //
  461. // - The app can specify a custom color map,
  462. // - The default color map maps colors beyond the 3D colors,
  463. // - strange UNIX stuff happens that I'm afraid to mess with.
  464. //
  465. HBITMAP CreateMappedBitmap(HINSTANCE hInstance, INT_PTR idBitmap,
  466. UINT wFlags, LPCOLORMAP lpColorMap, int iNumMaps)
  467. {
  468. HBITMAP hbm = NULL;
  469. BOOL bColorTable;
  470. HRSRC hrsrc = FindResource(hInstance, MAKEINTRESOURCE(idBitmap), RT_BITMAP);
  471. if (hrsrc)
  472. {
  473. HGLOBAL hglob = LoadResource(hInstance, hrsrc);
  474. LPBITMAPINFOHEADER pbihRes = (LPBITMAPINFOHEADER)LockResource(hglob);
  475. if (pbihRes)
  476. {
  477. // munge on a copy of the color table instead of the original
  478. // (prevent possibility of "reload" with messed table
  479. UINT cbOffset;
  480. LPBITMAPINFOHEADER pbih;
  481. WORD biBitCount = pbihRes->biBitCount;
  482. if ((biBitCount > 8) && (pbihRes->biCompression == BI_RGB))
  483. {
  484. // No bmiColors table, image bits start right after header
  485. cbOffset = pbihRes->biSize;
  486. bColorTable = FALSE;
  487. }
  488. else
  489. {
  490. // Bits start after bmiColors table
  491. cbOffset = pbihRes->biSize + ((1 << (pbihRes->biBitCount)) * sizeof(RGBQUAD));
  492. bColorTable = TRUE;
  493. }
  494. pbih = (LPBITMAPINFOHEADER)LocalAlloc(LPTR, cbOffset);
  495. if (pbih)
  496. {
  497. COLOR_STRUCT acsMask[MAX_COLOR_MAPS];
  498. LPBYTE lpBits = (LPBYTE)(pbihRes) + cbOffset;
  499. UINT uColorTableLength = (bColorTable ? ARRAYSIZE(acsMask) : 0);
  500. memcpy(pbih, pbihRes, cbOffset);
  501. if (bColorTable)
  502. _MapBitmapColors(pbih, lpColorMap, iNumMaps, acsMask, uColorTableLength, wFlags);
  503. hbm = _CreateMappedBitmap(pbih, lpBits, acsMask, uColorTableLength, wFlags);
  504. LocalFree(pbih);
  505. }
  506. UnlockResource(hglob);
  507. }
  508. FreeResource(hrsrc);
  509. }
  510. return hbm;
  511. }
  512. // moved from shelldll\dragdrop.c
  513. // should caller pass in message that indicates termination
  514. // (WM_LBUTTONUP, WM_RBUTTONUP)?
  515. //
  516. // in:
  517. // hwnd to do check on
  518. // x, y in client coordinates
  519. //
  520. // returns:
  521. // TRUE the user began to drag (moved mouse outside double click rect)
  522. // FALSE mouse came up inside click rect
  523. //
  524. // FEATURE, should support VK_ESCAPE to cancel
  525. BOOL CheckForDragBegin(HWND hwnd, int x, int y)
  526. {
  527. RECT rc;
  528. int dxClickRect = GetSystemMetrics(SM_CXDRAG);
  529. int dyClickRect = GetSystemMetrics(SM_CYDRAG);
  530. if (dxClickRect < 4)
  531. {
  532. dxClickRect = dyClickRect = 4;
  533. }
  534. // See if the user moves a certain number of pixels in any direction
  535. SetRect(&rc, x - dxClickRect, y - dyClickRect, x + dxClickRect, y + dyClickRect);
  536. MapWindowRect(hwnd, HWND_DESKTOP, &rc); // client -> screen
  537. //
  538. // SUBTLE! We use PeekMessage+WaitMessage instead of GetMessage,
  539. // because WaitMessage will return when there is an incoming
  540. // SendMessage, whereas GetMessage does not. This is important,
  541. // because the incoming message might've been WM_CAPTURECHANGED.
  542. //
  543. SetCapture(hwnd);
  544. do {
  545. MSG32 msg32;
  546. if (PeekMessage32(&msg32, NULL, 0, 0, PM_REMOVE, TRUE))
  547. {
  548. // See if the application wants to process the message...
  549. if (CallMsgFilter32(&msg32, MSGF_COMMCTRL_BEGINDRAG, TRUE) != 0)
  550. continue;
  551. switch (msg32.message) {
  552. case WM_LBUTTONUP:
  553. case WM_RBUTTONUP:
  554. case WM_LBUTTONDOWN:
  555. case WM_RBUTTONDOWN:
  556. ReleaseCapture();
  557. return FALSE;
  558. case WM_MOUSEMOVE:
  559. if (IsWindow(hwnd) && !PtInRect(&rc, msg32.pt)) {
  560. ReleaseCapture();
  561. return TRUE;
  562. }
  563. break;
  564. default:
  565. TranslateMessage32(&msg32, TRUE);
  566. DispatchMessage32(&msg32, TRUE);
  567. break;
  568. }
  569. }
  570. else WaitMessage();
  571. // WM_CANCELMODE messages will unset the capture, in that
  572. // case I want to exit this loop
  573. } while (IsWindow(hwnd) && GetCapture() == hwnd);
  574. return FALSE;
  575. }
  576. /* Regular StrToInt; stops at first non-digit. */
  577. int WINAPI StrToInt(LPCTSTR lpSrc) // atoi()
  578. {
  579. #define ISDIGIT(c) ((c) >= TEXT('0') && (c) <= TEXT('9'))
  580. int n = 0;
  581. BOOL bNeg = FALSE;
  582. if (*lpSrc == TEXT('-')) {
  583. bNeg = TRUE;
  584. lpSrc++;
  585. }
  586. while (ISDIGIT(*lpSrc)) {
  587. n *= 10;
  588. n += *lpSrc - TEXT('0');
  589. lpSrc++;
  590. }
  591. return bNeg ? -n : n;
  592. }
  593. //
  594. // Wrappers for StrToInt
  595. //
  596. int WINAPI StrToIntA(LPCSTR lpSrc) // atoi()
  597. {
  598. LPWSTR lpString;
  599. INT iResult;
  600. lpString = ProduceWFromA (CP_ACP, lpSrc);
  601. if (!lpString) {
  602. return 0;
  603. }
  604. iResult = StrToIntW(lpString);
  605. FreeProducedString (lpString);
  606. return iResult;
  607. }
  608. #undef StrToLong
  609. //
  610. // No need to Unicode this since it is not
  611. // exported.
  612. //
  613. LONG WINAPI StrToLong(LPCTSTR lpSrc) // atoi()
  614. {
  615. return StrToInt(lpSrc);
  616. }
  617. //
  618. // From zmouse.h in the Magellan SDK
  619. //
  620. #define MSH_MOUSEWHEEL TEXT("MSWHEEL_ROLLMSG")
  621. // Class name for Magellan/Z MSWHEEL window
  622. // use FindWindow to get hwnd to MSWHEEL
  623. #define MOUSEZ_CLASSNAME TEXT("MouseZ") // wheel window class
  624. #define MOUSEZ_TITLE TEXT("Magellan MSWHEEL") // wheel window title
  625. #define MSH_WHEELMODULE_CLASS (MOUSEZ_CLASSNAME)
  626. #define MSH_WHEELMODULE_TITLE (MOUSEZ_TITLE)
  627. #define MSH_SCROLL_LINES TEXT("MSH_SCROLL_LINES_MSG")
  628. #define DI_GETDRAGIMAGE TEXT("ShellGetDragImage") // Copied from Shlobj.w
  629. UINT g_msgMSWheel;
  630. UINT g_ucScrollLines = 3; /* default */
  631. int gcWheelDelta;
  632. UINT g_uDragImages;
  633. // --------------------------------------------------------------------------
  634. // _TrackMouseEvent() entrypoint
  635. //
  636. // calls TrackMouseEvent because we run on an OS where this exists
  637. //
  638. // --------------------------------------------------------------------------
  639. BOOL WINAPI _TrackMouseEvent(LPTRACKMOUSEEVENT lpTME)
  640. {
  641. return TrackMouseEvent(lpTME);
  642. }
  643. //
  644. // Checks the process to see if it is running under the system SID
  645. //
  646. BOOL IsSystemProcess()
  647. {
  648. BOOL bRet = FALSE; // assume we are not a system process
  649. HANDLE hProcessToken;
  650. if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hProcessToken))
  651. {
  652. PSID pSIDSystem;
  653. static SID_IDENTIFIER_AUTHORITY sSystemSidAuthority = SECURITY_NT_AUTHORITY;
  654. if (AllocateAndInitializeSid(&sSystemSidAuthority,
  655. 1,
  656. SECURITY_LOCAL_SYSTEM_RID,
  657. 0, 0, 0, 0, 0, 0, 0,
  658. &pSIDSystem))
  659. {
  660. CheckTokenMembership(hProcessToken, pSIDSystem, &bRet);
  661. FreeSid(pSIDSystem);
  662. }
  663. CloseHandle(hProcessToken);
  664. }
  665. return bRet;
  666. }
  667. //
  668. // !! WARNING !! - Be very careful about opening HKCU in InitGlobalMetrics(). Basically this gets
  669. // called during processattach and system process will end up loading the user hive
  670. // and because advapi32 is lame we end up pinning the hive for the life of this process.
  671. //
  672. void InitGlobalMetrics(WPARAM wParam)
  673. {
  674. static BOOL fInitMouseWheel;
  675. static HWND hwndMSWheel;
  676. static UINT msgMSWheelGetScrollLines;
  677. HDC hdcScreen;
  678. BOOL fRemoteSession = (BOOL)GetSystemMetrics( SM_REMOTESESSION );
  679. if (!fInitMouseWheel)
  680. {
  681. fInitMouseWheel = TRUE;
  682. g_msgMSWheel = WM_MOUSEWHEEL;
  683. }
  684. g_uDragImages = RegisterWindowMessage(DI_GETDRAGIMAGE);
  685. SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &g_ucScrollLines, 0);
  686. g_cxIcon = GetSystemMetrics(SM_CXICON);
  687. g_cyIcon = GetSystemMetrics(SM_CYICON);
  688. g_cxSmIcon = GetSystemMetrics(SM_CXSMICON);
  689. g_cySmIcon = GetSystemMetrics(SM_CYSMICON);
  690. g_cxIconSpacing = GetSystemMetrics( SM_CXICONSPACING );
  691. g_cyIconSpacing = GetSystemMetrics( SM_CYICONSPACING );
  692. hdcScreen = GetDC(NULL);
  693. if (hdcScreen)
  694. {
  695. g_iDPI = GetDeviceCaps(hdcScreen, LOGPIXELSX);
  696. g_dScaleX = GetDeviceCaps(hdcScreen, LOGPIXELSX) / 96.0;
  697. g_dScaleY = GetDeviceCaps(hdcScreen, LOGPIXELSY) / 96.0;
  698. if (g_dScaleX > 1.0 ||
  699. g_dScaleY > 1.0)
  700. {
  701. g_fScale = TRUE;
  702. }
  703. ReleaseDC(NULL, hdcScreen);
  704. }
  705. // Full window drag stays off if running remotely. Sessions could become remote after
  706. // being started.
  707. if (!fRemoteSession &&
  708. (wParam == 0 || wParam == SPI_SETDRAGFULLWINDOWS))
  709. {
  710. SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, sizeof(g_fDragFullWindows), &g_fDragFullWindows, 0);
  711. }
  712. if (wParam == 0 || wParam == SPI_SETHIGHCONTRAST)
  713. {
  714. HIGHCONTRAST hc = {sizeof(hc)};
  715. if (SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(hc), &hc, 0))
  716. {
  717. g_fHighContrast = (hc.dwFlags & HCF_HIGHCONTRASTON);
  718. }
  719. }
  720. // Smooth scrolling stays off if running remotely
  721. if (!fRemoteSession)
  722. {
  723. g_fSmoothScroll = TRUE;
  724. //
  725. // (see warning at the top of this fn.)
  726. //
  727. // we want to avoid loading the users hive if we are running as a system process since advapi32
  728. // will hold the hive for as long as this process exists
  729. if (!IsSystemProcess())
  730. {
  731. HKEY hkey;
  732. if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, KEY_READ, &hkey) == ERROR_SUCCESS)
  733. {
  734. DWORD dwSize = sizeof(g_fSmoothScroll);
  735. RegQueryValueEx(hkey, TEXT("SmoothScroll"), 0, NULL, (LPBYTE)&g_fSmoothScroll, &dwSize);
  736. RegCloseKey(hkey);
  737. }
  738. }
  739. }
  740. if (fRemoteSession)
  741. {
  742. // Nobody should've turned these on
  743. g_fDragFullWindows = FALSE;
  744. g_fSmoothScroll = FALSE;
  745. }
  746. // some of these are also not members of NONCLIENTMETRICS
  747. if ((wParam == 0) || (wParam == SPI_SETNONCLIENTMETRICS))
  748. {
  749. NONCLIENTMETRICS ncm;
  750. // REVIEW, make sure all these vars are used somewhere.
  751. g_cxEdgeScaled = g_cxEdge = GetSystemMetrics(SM_CXEDGE);
  752. g_cyEdgeScaled = g_cyEdge = GetSystemMetrics(SM_CYEDGE);
  753. CCDPIScaleX(&g_cxEdgeScaled);
  754. CCDPIScaleY(&g_cyEdgeScaled);
  755. g_cxBorder = GetSystemMetrics(SM_CXBORDER);
  756. g_cyBorder = GetSystemMetrics(SM_CYBORDER);
  757. g_cxScreen = GetSystemMetrics(SM_CXSCREEN);
  758. g_cyScreen = GetSystemMetrics(SM_CYSCREEN);
  759. g_cxFrame = GetSystemMetrics(SM_CXFRAME);
  760. g_cyFrame = GetSystemMetrics(SM_CYFRAME);
  761. ncm.cbSize = sizeof(ncm);
  762. SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
  763. g_cxVScroll = g_cxScrollbar = (int)ncm.iScrollWidth;
  764. g_cyHScroll = g_cyScrollbar = (int)ncm.iScrollHeight;
  765. // this is true for 4.0 modules only
  766. // for 3.x modules user lies and adds one to these values
  767. // ASSERT(g_cxVScroll == GetSystemMetrics(SM_CXVSCROLL));
  768. // ASSERT(g_cyHScroll == GetSystemMetrics(SM_CYHSCROLL));
  769. g_cxIconMargin = g_cxBorder * 8;
  770. g_cyIconMargin = g_cyEdge;
  771. g_cyLabelSpace = g_cyIconMargin + (g_cyEdge);
  772. g_cxLabelMargin = g_cxEdge;
  773. g_cxDoubleClk = GetSystemMetrics(SM_CXDOUBLECLK);
  774. g_cyDoubleClk = GetSystemMetrics(SM_CYDOUBLECLK);
  775. g_fEnableBalloonTips = SHRegGetBoolUSValue(REGSTR_EXPLORER_ADVANCED, TEXT("EnableBalloonTips"),
  776. FALSE, // Don't ignore HKCU
  777. TRUE);
  778. }
  779. SystemParametersInfo(SPI_GETMENUDROPALIGNMENT, 0, &g_fLeftAligned, 0);
  780. //NT 4.0 has this SPI_GETMOUSEHOVERTIME
  781. SystemParametersInfo(SPI_GETMOUSEHOVERTIME, 0, &g_dwHoverSelectTimeout, 0);
  782. }
  783. void RelayToToolTips(HWND hwndToolTips, HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  784. {
  785. if(hwndToolTips)
  786. {
  787. MSG msg;
  788. msg.lParam = lParam;
  789. msg.wParam = wParam;
  790. msg.message = wMsg;
  791. msg.hwnd = hWnd;
  792. SendMessage(hwndToolTips, TTM_RELAYEVENT, 0, (LPARAM)(LPMSG)&msg);
  793. }
  794. }
  795. #define DT_SEARCHTIMEOUT 1000L // 1 seconds
  796. __inline BOOL IsISearchTimedOut(PISEARCHINFO pis)
  797. {
  798. return GetMessageTime() - pis->timeLast > DT_SEARCHTIMEOUT &&
  799. !IsFlagSet(g_dwPrototype, PTF_NOISEARCHTO);
  800. }
  801. int GetIncrementSearchString(PISEARCHINFO pis, LPTSTR lpsz)
  802. {
  803. if (IsISearchTimedOut(pis))
  804. {
  805. pis->iIncrSearchFailed = 0;
  806. pis->ichCharBuf = 0;
  807. }
  808. if (pis->ichCharBuf && lpsz) {
  809. lstrcpyn(lpsz, pis->pszCharBuf, pis->ichCharBuf + 1);
  810. lpsz[pis->ichCharBuf] = TEXT('\0');
  811. }
  812. return pis->ichCharBuf;
  813. }
  814. // Now only Korean version is interested in incremental search with composition string.
  815. BOOL IncrementSearchImeCompStr(PISEARCHINFO pis, BOOL fCompStr, LPTSTR lpszCompStr, LPTSTR *lplpstr)
  816. {
  817. BOOL fRestart = FALSE;
  818. if (!pis->fReplaceCompChar && IsISearchTimedOut(pis))
  819. {
  820. pis->iIncrSearchFailed = 0;
  821. pis->ichCharBuf = 0;
  822. }
  823. if (pis->ichCharBuf == 0)
  824. {
  825. fRestart = TRUE;
  826. pis->fReplaceCompChar = FALSE;
  827. }
  828. pis->timeLast = GetMessageTime();
  829. // Is there room for new character plus zero terminator?
  830. //
  831. if (!pis->fReplaceCompChar && pis->ichCharBuf + 1 + 1 > pis->cbCharBuf)
  832. {
  833. LPTSTR psz = ReAlloc(pis->pszCharBuf, sizeof(TCHAR)*(pis->cbCharBuf + 16));
  834. if (!psz)
  835. return fRestart;
  836. pis->cbCharBuf += 16;
  837. pis->pszCharBuf = psz;
  838. }
  839. if (pis->fReplaceCompChar)
  840. {
  841. if (lpszCompStr[0])
  842. {
  843. pis->pszCharBuf[pis->ichCharBuf-1] = lpszCompStr[0];
  844. pis->pszCharBuf[pis->ichCharBuf] = 0;
  845. }
  846. else
  847. {
  848. pis->ichCharBuf--;
  849. pis->pszCharBuf[pis->ichCharBuf] = 0;
  850. }
  851. }
  852. else
  853. {
  854. pis->pszCharBuf[pis->ichCharBuf++] = lpszCompStr[0];
  855. pis->pszCharBuf[pis->ichCharBuf] = 0;
  856. }
  857. pis->fReplaceCompChar = (fCompStr && lpszCompStr[0]);
  858. if (pis->ichCharBuf == 1 && pis->fReplaceCompChar)
  859. fRestart = TRUE;
  860. *lplpstr = pis->pszCharBuf;
  861. return fRestart;
  862. }
  863. /*
  864. * Thunk for LVM_GETISEARCHSTRINGA
  865. */
  866. int GetIncrementSearchStringA(PISEARCHINFO pis, UINT uiCodePage, LPSTR lpsz)
  867. {
  868. if (IsISearchTimedOut(pis))
  869. {
  870. pis->iIncrSearchFailed = 0;
  871. pis->ichCharBuf = 0;
  872. }
  873. if (pis->ichCharBuf && lpsz) {
  874. ConvertWToAN( uiCodePage, lpsz, pis->ichCharBuf, pis->pszCharBuf, pis->ichCharBuf );
  875. lpsz[pis->ichCharBuf] = '\0';
  876. }
  877. return pis->ichCharBuf;
  878. }
  879. // Beep only on the first failure.
  880. void IncrementSearchBeep(PISEARCHINFO pis)
  881. {
  882. if (!pis->iIncrSearchFailed)
  883. {
  884. pis->iIncrSearchFailed = TRUE;
  885. MessageBeep(0);
  886. }
  887. }
  888. //
  889. // IncrementSearchString - Add or clear the search string
  890. //
  891. // ch == 0: Reset the search string. Return value meaningless.
  892. //
  893. // ch != 0: Append the character to the search string, starting
  894. // a new search string if we timed out the last one.
  895. // lplpstr receives the string so far.
  896. // Return value is TRUE if a new search string was
  897. // created, or FALSE if we appended to an existing one.
  898. //
  899. BOOL IncrementSearchString(PISEARCHINFO pis, UINT ch, LPTSTR *lplpstr)
  900. {
  901. BOOL fRestart = FALSE;
  902. if (!ch) {
  903. pis->ichCharBuf =0;
  904. pis->iIncrSearchFailed = 0;
  905. return FALSE;
  906. }
  907. if (IsISearchTimedOut(pis))
  908. {
  909. pis->iIncrSearchFailed = 0;
  910. pis->ichCharBuf = 0;
  911. }
  912. if (pis->ichCharBuf == 0)
  913. fRestart = TRUE;
  914. pis->timeLast = GetMessageTime();
  915. // Is there room for new character plus zero terminator?
  916. //
  917. if (pis->ichCharBuf + 1 + 1 > pis->cbCharBuf)
  918. {
  919. LPTSTR psz = ReAlloc(pis->pszCharBuf, ((pis->cbCharBuf + 16) * sizeof(TCHAR)));
  920. if (!psz)
  921. return fRestart;
  922. pis->cbCharBuf += 16;
  923. pis->pszCharBuf = psz;
  924. }
  925. pis->pszCharBuf[pis->ichCharBuf++] = (TCHAR)ch;
  926. pis->pszCharBuf[pis->ichCharBuf] = 0;
  927. *lplpstr = pis->pszCharBuf;
  928. return fRestart;
  929. }
  930. // strips out the accelerators. they CAN be the same buffers.
  931. int StripAccelerators(LPTSTR lpszFrom, LPTSTR lpszTo, BOOL fAmpOnly)
  932. {
  933. LPTSTR lpszStart = lpszTo;
  934. while (*lpszTo = *lpszFrom)
  935. {
  936. if (!fAmpOnly && (g_fDBCSInputEnabled))
  937. {
  938. if (*lpszFrom == TEXT('(') && *(lpszFrom + 1) == CH_PREFIX)
  939. {
  940. int i;
  941. LPTSTR psz = lpszFrom + 2;
  942. for(i = 0; i < 2 && *psz; i++, psz = FastCharNext(psz))
  943. {
  944. ;
  945. }
  946. if (*psz == '\0')
  947. {
  948. *lpszTo = 0;
  949. break;
  950. }
  951. else if (i == 2 && *psz == TEXT(')'))
  952. {
  953. lpszTo--;
  954. lpszFrom = psz+1;
  955. continue;
  956. }
  957. }
  958. }
  959. if (*lpszFrom == TEXT('\t'))
  960. {
  961. *lpszTo = TEXT('\0');
  962. break;
  963. }
  964. if ((*lpszFrom++ != CH_PREFIX) || (*lpszFrom == CH_PREFIX))
  965. {
  966. lpszTo++;
  967. }
  968. }
  969. return (int)(lpszTo - lpszStart);
  970. }
  971. void ScrollShrinkRect(int x, int y, LPRECT lprc)
  972. {
  973. if (lprc) {
  974. if (x > 0) {
  975. lprc->left += x;
  976. } else {
  977. lprc->right += x;
  978. }
  979. if (y > 0) {
  980. lprc->top += y;
  981. } else {
  982. lprc->bottom += y;
  983. }
  984. }
  985. }
  986. // common control info helpers
  987. void CIInitialize(LPCCONTROLINFO lpci, HWND hwnd, LPCREATESTRUCT lpcs)
  988. {
  989. TEXTMETRIC tm;
  990. HFONT hfStatus;
  991. lpci->hwnd = hwnd;
  992. lpci->hwndParent = lpcs->hwndParent;
  993. lpci->style = lpcs->style;
  994. lpci->uiCodePage = CP_ACP;
  995. lpci->dwExStyle = lpcs->dwExStyle;
  996. lpci->iVersion = 6;
  997. #ifdef DPITEST
  998. lpci->fDPIAware = TRUE;
  999. #endif
  1000. // See if the default listview font has no internal leading.
  1001. // If not, then we have to inflate the focus rectangle so we
  1002. // don't overlap the first pixel.
  1003. //
  1004. // Note that this is a global and not per-TextOut.
  1005. // Otherwise controls with a mix of fonts will get
  1006. // inconsistently-placed focus rectangles.
  1007. //
  1008. hfStatus = CCCreateStatusFont();
  1009. if (hfStatus)
  1010. {
  1011. HDC hdc = GetDC(hwnd);
  1012. if (hdc)
  1013. {
  1014. HFONT hfPrev = SelectFont(hdc, hfStatus);
  1015. if (GetTextMetrics(hdc, &tm) &&
  1016. tm.tmInternalLeading == 0)
  1017. {
  1018. g_cyCompensateInternalLeading = 1;
  1019. }
  1020. SelectFont(hdc, hfPrev);
  1021. ReleaseDC(hwnd, hdc);
  1022. }
  1023. DeleteObject(hfStatus);
  1024. }
  1025. lpci->bUnicode = lpci->hwndParent &&
  1026. SendMessage (lpci->hwndParent, WM_NOTIFYFORMAT,
  1027. (WPARAM)lpci->hwnd, NF_QUERY) == NFR_UNICODE;
  1028. if (lpci->hwndParent)
  1029. {
  1030. LRESULT lRes = SendMessage(lpci->hwndParent, WM_QUERYUISTATE, 0, 0);
  1031. lpci->wUIState = LOWORD(lRes);
  1032. }
  1033. }
  1034. LRESULT CIHandleNotifyFormat(LPCCONTROLINFO lpci, LPARAM lParam)
  1035. {
  1036. if (lParam == NF_QUERY)
  1037. {
  1038. return NFR_UNICODE;
  1039. }
  1040. else if (lParam == NF_REQUERY)
  1041. {
  1042. LRESULT uiResult;
  1043. uiResult = SendMessage (lpci->hwndParent, WM_NOTIFYFORMAT,
  1044. (WPARAM)lpci->hwnd, NF_QUERY);
  1045. lpci->bUnicode = BOOLIFY(uiResult == NFR_UNICODE);
  1046. return uiResult;
  1047. }
  1048. return 0;
  1049. }
  1050. UINT CCSwapKeys(WPARAM wParam, UINT vk1, UINT vk2)
  1051. {
  1052. if (wParam == vk1)
  1053. return vk2;
  1054. if (wParam == vk2)
  1055. return vk1;
  1056. return (UINT)wParam;
  1057. }
  1058. UINT RTLSwapLeftRightArrows(CCONTROLINFO *pci, WPARAM wParam)
  1059. {
  1060. if (pci->dwExStyle & RTL_MIRRORED_WINDOW)
  1061. {
  1062. return CCSwapKeys(wParam, VK_LEFT, VK_RIGHT);
  1063. }
  1064. return (UINT)wParam;
  1065. }
  1066. //
  1067. // New for v5.01:
  1068. //
  1069. // Accessibility (and some other callers, sometimes even us) relies on
  1070. // a XXM_GETITEM call filling the buffer and not just redirecting the
  1071. // pointer. Accessibility is particularly impacted by this because they
  1072. // live outside the process, so the redirected pointer means nothing
  1073. // to them. Here, we copy the result back into the app buffer and return
  1074. // the raw pointer. The caller will return the raw pointer back to the
  1075. // app, so the answer is in two places, either the app buffer, or in
  1076. // the raw pointer.
  1077. //
  1078. // Usage:
  1079. //
  1080. // if (nm.item.mask & LVIF_TEXT)
  1081. // pitem->pszText = CCReturnDispInfoText(nm.item.pszText,
  1082. // pitem->pszText, pitem->cchTextMax);
  1083. //
  1084. LPTSTR CCReturnDispInfoText(LPTSTR pszSrc, LPTSTR pszDest, UINT cchDest)
  1085. {
  1086. // Test pszSrc != pszDest first since the common case is that they
  1087. // are equal.
  1088. if (pszSrc != pszDest && !IsFlagPtr(pszSrc) && !IsFlagPtr(pszDest))
  1089. StrCpyN(pszDest, pszSrc, cchDest);
  1090. return pszSrc;
  1091. }
  1092. #define SUBSCROLLS 100
  1093. #define abs(x) ( ( x > 0 ) ? x : -x)
  1094. #define DEFAULT_MAXSCROLLTIME ((GetDoubleClickTime() / 2) + 1) // Ensure >= 1
  1095. #define DEFAULT_MINSCROLL 8
  1096. int SmoothScrollWindow(PSMOOTHSCROLLINFO psi)
  1097. {
  1098. int dx = psi->dx;
  1099. int dy = psi->dy;
  1100. LPCRECT lprcSrc = psi->lprcSrc;
  1101. LPCRECT lprcClip = psi->lprcClip;
  1102. HRGN hrgnUpdate = psi->hrgnUpdate;
  1103. LPRECT lprcUpdate = psi->lprcUpdate;
  1104. UINT fuScroll = psi->fuScroll;
  1105. int iRet = SIMPLEREGION;
  1106. RECT rcUpdate;
  1107. RECT rcSrc;
  1108. RECT rcClip;
  1109. int xStep;
  1110. int yStep;
  1111. int iSlicesDone = 0;
  1112. int iSlices;
  1113. DWORD dwTimeStart, dwTimeNow;
  1114. HRGN hrgnLocalUpdate;
  1115. UINT cxMinScroll = psi->cxMinScroll;
  1116. UINT cyMinScroll = psi->cyMinScroll;
  1117. UINT uMaxScrollTime = psi->uMaxScrollTime;
  1118. int iSubScrolls;
  1119. PFNSMOOTHSCROLLPROC pfnScrollProc;
  1120. DWORD dwRedrawFlags = RDW_ERASE | RDW_ERASENOW | RDW_INVALIDATE;
  1121. if (!lprcUpdate)
  1122. lprcUpdate = &rcUpdate;
  1123. SetRectEmpty(lprcUpdate);
  1124. if (psi->cbSize != sizeof(SMOOTHSCROLLINFO))
  1125. {
  1126. return 0;
  1127. }
  1128. // check the defaults
  1129. if (!(psi->fMask & SSIF_MINSCROLL )
  1130. || cxMinScroll == SSI_DEFAULT)
  1131. {
  1132. cxMinScroll = DEFAULT_MINSCROLL;
  1133. }
  1134. if (!(psi->fMask & SSIF_MINSCROLL)
  1135. || cyMinScroll == SSI_DEFAULT)
  1136. {
  1137. cyMinScroll = DEFAULT_MINSCROLL;
  1138. }
  1139. if (!(psi->fMask & SSIF_MAXSCROLLTIME)
  1140. || uMaxScrollTime == SSI_DEFAULT)
  1141. {
  1142. uMaxScrollTime = DEFAULT_MAXSCROLLTIME;
  1143. }
  1144. if (uMaxScrollTime < SUBSCROLLS)
  1145. {
  1146. uMaxScrollTime = SUBSCROLLS;
  1147. }
  1148. if ((!(fuScroll & SSW_EX_IGNORESETTINGS)) &&
  1149. (!g_fSmoothScroll))
  1150. {
  1151. fuScroll |= SSW_EX_IMMEDIATE;
  1152. }
  1153. if ((psi->fMask & SSIF_SCROLLPROC) && psi->pfnScrollProc)
  1154. {
  1155. pfnScrollProc = psi->pfnScrollProc;
  1156. }
  1157. else
  1158. {
  1159. pfnScrollProc = ScrollWindowEx;
  1160. }
  1161. #ifdef ScrollWindowEx
  1162. #undef ScrollWindowEx
  1163. #endif
  1164. if (fuScroll & SSW_EX_IMMEDIATE)
  1165. {
  1166. return pfnScrollProc(psi->hwnd, dx, dy, lprcSrc, lprcClip, hrgnUpdate,
  1167. lprcUpdate, LOWORD(fuScroll));
  1168. }
  1169. if (fuScroll & SSW_EX_UPDATEATEACHSTEP)
  1170. {
  1171. dwRedrawFlags |= RDW_UPDATENOW;
  1172. }
  1173. // copy input rects locally
  1174. if (lprcSrc)
  1175. {
  1176. rcSrc = *lprcSrc;
  1177. lprcSrc = &rcSrc;
  1178. }
  1179. if (lprcClip)
  1180. {
  1181. rcClip = *lprcClip;
  1182. lprcClip = &rcClip;
  1183. }
  1184. if (!hrgnUpdate)
  1185. hrgnLocalUpdate = CreateRectRgn(0,0,0,0);
  1186. else
  1187. hrgnLocalUpdate = hrgnUpdate;
  1188. //set up initial vars
  1189. dwTimeStart = GetTickCount();
  1190. if (fuScroll & SSW_EX_NOTIMELIMIT)
  1191. {
  1192. xStep = cxMinScroll * (dx < 0 ? -1 : 1);
  1193. yStep = cyMinScroll * (dy < 0 ? -1 : 1);
  1194. }
  1195. else
  1196. {
  1197. iSubScrolls = (uMaxScrollTime / DEFAULT_MAXSCROLLTIME) * SUBSCROLLS;
  1198. if (!iSubScrolls)
  1199. iSubScrolls = SUBSCROLLS;
  1200. xStep = dx / iSubScrolls;
  1201. yStep = dy / iSubScrolls;
  1202. }
  1203. if (xStep == 0 && dx)
  1204. xStep = dx < 0 ? -1 : 1;
  1205. if (yStep == 0 && dy)
  1206. yStep = dy < 0 ? -1 : 1;
  1207. while (dx || dy)
  1208. {
  1209. int x,y;
  1210. RECT rcTempUpdate;
  1211. if (fuScroll & SSW_EX_NOTIMELIMIT)
  1212. {
  1213. x = xStep;
  1214. y = yStep;
  1215. if (abs(x) > abs(dx))
  1216. x = dx;
  1217. if (abs(y) > abs(dy))
  1218. y = dy;
  1219. }
  1220. else
  1221. {
  1222. int iTimePerScroll = uMaxScrollTime / iSubScrolls;
  1223. if (!iTimePerScroll)
  1224. iTimePerScroll = 1;
  1225. dwTimeNow = GetTickCount();
  1226. iSlices = ((dwTimeNow - dwTimeStart) / iTimePerScroll) - iSlicesDone;
  1227. if (iSlices < 0)
  1228. iSlices = 0;
  1229. do
  1230. {
  1231. int iRet = 0;
  1232. iSlices++;
  1233. if ((iSlicesDone + iSlices) <= iSubScrolls)
  1234. {
  1235. x = xStep * iSlices;
  1236. y = yStep * iSlices;
  1237. // this could go over if we rounded ?Step up to 1(-1) above
  1238. if (abs(x) > abs(dx))
  1239. x = dx;
  1240. if (abs(y) > abs(dy))
  1241. y = dy;
  1242. }
  1243. else
  1244. {
  1245. x = dx;
  1246. y = dy;
  1247. }
  1248. //DebugMsg(DM_TRACE, "SmoothScrollWindowCallback %d", iRet);
  1249. if (x == dx && y == dy)
  1250. break;
  1251. if ((((UINT)(abs(x)) >= cxMinScroll) || !x) &&
  1252. (((UINT)(abs(y)) >= cyMinScroll) || !y))
  1253. break;
  1254. }
  1255. while (1);
  1256. }
  1257. if (pfnScrollProc(psi->hwnd, x, y, lprcSrc, lprcClip, hrgnLocalUpdate, &rcTempUpdate, LOWORD(fuScroll)) == ERROR)
  1258. {
  1259. iRet = ERROR;
  1260. goto Bail;
  1261. }
  1262. UnionRect(lprcUpdate, &rcTempUpdate, lprcUpdate);
  1263. RedrawWindow(psi->hwnd, NULL, hrgnLocalUpdate, dwRedrawFlags);
  1264. ScrollShrinkRect(x,y, (LPRECT)lprcSrc);
  1265. dx -= x;
  1266. dy -= y;
  1267. iSlicesDone += iSlices;
  1268. }
  1269. Bail:
  1270. if (fuScroll & SW_SCROLLCHILDREN)
  1271. {
  1272. RedrawWindow(psi->hwnd, lprcUpdate, NULL, RDW_ERASE | RDW_UPDATENOW | RDW_INVALIDATE);
  1273. }
  1274. if (hrgnLocalUpdate != hrgnUpdate)
  1275. DeleteObject(hrgnLocalUpdate);
  1276. return iRet;
  1277. }
  1278. #define CCH_KEYMAX 256
  1279. void CCPlaySound(LPCTSTR lpszName)
  1280. {
  1281. TCHAR szFileName[MAX_PATH];
  1282. LONG cbSize = SIZEOF(szFileName);
  1283. TCHAR szKey[CCH_KEYMAX];
  1284. // check the registry first
  1285. // if there's nothing registered, we blow off the play,
  1286. // but we don't set the MM_DONTLOAD flag so taht if they register
  1287. // something we will play it
  1288. wsprintf(szKey, TEXT("AppEvents\\Schemes\\Apps\\.Default\\%s\\.current"), lpszName);
  1289. if ((RegQueryValue(HKEY_CURRENT_USER, szKey, szFileName, &cbSize) == ERROR_SUCCESS) &&
  1290. (cbSize > SIZEOF(szFileName[0])))
  1291. {
  1292. PlaySound(szFileName, NULL, SND_FILENAME | SND_ASYNC);
  1293. }
  1294. }
  1295. BOOL CCForwardEraseBackground(HWND hwnd, HDC hdc)
  1296. {
  1297. HWND hwndParent = GetParent(hwnd);
  1298. LRESULT lres = 0;
  1299. if (hwndParent)
  1300. {
  1301. // Adjust the origin so the parent paints in the right place
  1302. POINT pt = {0,0};
  1303. MapWindowPoints(hwnd, hwndParent, &pt, 1);
  1304. OffsetWindowOrgEx(hdc,
  1305. pt.x,
  1306. pt.y,
  1307. &pt);
  1308. lres = SendMessage(hwndParent, WM_ERASEBKGND, (WPARAM) hdc, 0L);
  1309. SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
  1310. }
  1311. return(lres != 0);
  1312. }
  1313. HFONT CCGetHotFont(HFONT hFont, HFONT *phFontHot)
  1314. {
  1315. if (!*phFontHot) {
  1316. LOGFONT lf;
  1317. // create the underline font
  1318. GetObject(hFont, sizeof(lf), &lf);
  1319. #ifndef DONT_UNDERLINE
  1320. lf.lfUnderline = TRUE;
  1321. #endif
  1322. *phFontHot = CreateFontIndirect(&lf);
  1323. }
  1324. return *phFontHot;
  1325. }
  1326. HFONT CCCreateStatusFont(void)
  1327. {
  1328. NONCLIENTMETRICS ncm;
  1329. ncm.cbSize = sizeof(NONCLIENTMETRICS);
  1330. SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
  1331. return CreateFontIndirect(&ncm.lfStatusFont);
  1332. }
  1333. HFONT CCCreateUnderlineFont(HFONT hf)
  1334. {
  1335. HFONT hUnderline = NULL;
  1336. LOGFONT lf;
  1337. if (hf && GetObject(hf, sizeof(lf), &lf))
  1338. {
  1339. lf.lfUnderline = TRUE;
  1340. hUnderline = CreateFontIndirect(&lf);
  1341. }
  1342. return hUnderline;
  1343. }
  1344. void* CCLocalReAlloc(void* p, UINT uBytes)
  1345. {
  1346. if (uBytes) {
  1347. if (p) {
  1348. return LocalReAlloc(p, uBytes, LMEM_MOVEABLE | LMEM_ZEROINIT);
  1349. } else {
  1350. return LocalAlloc(LPTR, uBytes);
  1351. }
  1352. } else {
  1353. if (p)
  1354. LocalFree(p);
  1355. return NULL;
  1356. }
  1357. }
  1358. /*----------------------------------------------------------
  1359. Purpose: This function provides the commctrl version info. This
  1360. allows the caller to distinguish running NT SUR vs.
  1361. Win95 shell vs. Nashville, etc.
  1362. This API was not supplied in Win95 or NT SUR, so
  1363. the caller must GetProcAddress it. If this fails,
  1364. the caller is running on Win95 or NT SUR.
  1365. Returns: NO_ERROR
  1366. ERROR_INVALID_PARAMETER if pinfo is invalid
  1367. Cond: --
  1368. */
  1369. // All we have to do is declare this puppy and CCDllGetVersion does the rest
  1370. // Note that we use VER_FILEVERSION_DW because comctl32 uses a funky
  1371. // version scheme
  1372. DLLVER_DUALBINARY(VER_FILEVERSION_DW, VER_PRODUCTBUILD_QFE);
  1373. //
  1374. // Translate the given font to a code page used for thunking text
  1375. //
  1376. UINT GetCodePageForFont (HFONT hFont)
  1377. {
  1378. #ifdef WINNT
  1379. LOGFONT lf;
  1380. TCHAR szFontName[MAX_PATH];
  1381. CHARSETINFO csi;
  1382. DWORD dwSize, dwType;
  1383. HKEY hKey;
  1384. if (!GetObject (hFont, sizeof(lf), &lf)) {
  1385. return CP_ACP;
  1386. }
  1387. //
  1388. // Check for font substitutes
  1389. //
  1390. lstrcpy (szFontName, lf.lfFaceName);
  1391. if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  1392. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes"),
  1393. 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
  1394. dwSize = MAX_PATH * sizeof(TCHAR);
  1395. RegQueryValueEx (hKey, lf.lfFaceName, NULL, &dwType,
  1396. (LPBYTE) szFontName, &dwSize);
  1397. RegCloseKey (hKey);
  1398. }
  1399. //
  1400. // This is to fix office for locales that use non 1252 versions
  1401. // of Ms Sans Serif and Ms Serif. These fonts incorrectly identify
  1402. // themselves as having an Ansi charset, so TranslateCharsetInfo will
  1403. // return the wrong value.
  1404. //
  1405. // NT bug 260697: Office 2000 uses Tahoma.
  1406. //
  1407. if ((lf.lfCharSet == ANSI_CHARSET) &&
  1408. (!lstrcmpi(L"Helv", szFontName) ||
  1409. !lstrcmpi(L"Ms Sans Serif", szFontName) ||
  1410. !lstrcmpi(L"Ms Serif", szFontName) ||
  1411. !lstrcmpi(L"Tahoma", szFontName)))
  1412. {
  1413. return CP_ACP;
  1414. }
  1415. //
  1416. // This is to fix FE office95a and Pro. msofe95.dll sets wrong charset when create
  1417. // listview control. so TranslateCharsetInfo will return the wrong value.
  1418. // Korea : DotumChe.
  1419. // Taiwan : New MingLight
  1420. // China : SongTi
  1421. if ((lf.lfCharSet == SHIFTJIS_CHARSET) &&
  1422. (!lstrcmpi(L"\xb3cb\xc6c0\xccb4", lf.lfFaceName)) || // Korea
  1423. (!lstrcmpi(L"\x65b0\x7d30\x660e\x9ad4", lf.lfFaceName)) || // Taiwan
  1424. (!lstrcmpi(L"\x5b8b\x4f53", lf.lfFaceName))) // PRC
  1425. {
  1426. return CP_ACP;
  1427. }
  1428. if (!TranslateCharsetInfo((DWORD *) lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
  1429. return CP_ACP;
  1430. }
  1431. return csi.ciACP;
  1432. #else
  1433. return CP_ACP;
  1434. #endif
  1435. }
  1436. LONG GetMessagePosClient(HWND hwnd, LPPOINT ppt)
  1437. {
  1438. LPARAM lParam;
  1439. POINT pt;
  1440. if (!ppt)
  1441. ppt = &pt;
  1442. lParam = GetMessagePos();
  1443. ppt->x = GET_X_LPARAM(lParam);
  1444. ppt->y = GET_Y_LPARAM(lParam);
  1445. ScreenToClient(hwnd, ppt);
  1446. return MAKELONG(ppt->x, ppt->y);
  1447. }
  1448. LPTSTR StrDup(LPCTSTR lpsz)
  1449. {
  1450. LPTSTR lpszRet = (LPTSTR)LocalAlloc(LPTR, (lstrlen(lpsz) + 1) * sizeof(TCHAR));
  1451. if (lpszRet) {
  1452. lstrcpy(lpszRet, lpsz);
  1453. }
  1454. return lpszRet;
  1455. }
  1456. #ifdef UNICODE
  1457. LPSTR StrDupA(LPCSTR lpsz)
  1458. {
  1459. LPSTR lpszRet = (LPSTR)LocalAlloc(LPTR, (lstrlenA(lpsz) + 1) * sizeof(CHAR));
  1460. if (lpszRet) {
  1461. lstrcpyA(lpszRet, lpsz);
  1462. }
  1463. return lpszRet;
  1464. }
  1465. #endif
  1466. HWND GetDlgItemRect(HWND hDlg, int nIDItem, LPRECT prc) //relative to hDlg
  1467. {
  1468. HWND hCtrl = NULL;
  1469. if (prc)
  1470. {
  1471. hCtrl = GetDlgItem(hDlg, nIDItem);
  1472. if (hCtrl)
  1473. {
  1474. GetWindowRect(hCtrl, prc);
  1475. MapWindowRect(NULL, hDlg, prc);
  1476. }
  1477. else
  1478. SetRectEmpty(prc);
  1479. }
  1480. return hCtrl;
  1481. }
  1482. /*----------------------------------------------------------
  1483. Purpose: Calls the ADVPACK entry-point which executes an inf
  1484. file section.
  1485. */
  1486. HRESULT CallRegInstall(LPSTR szSection)
  1487. {
  1488. HRESULT hr = E_FAIL;
  1489. HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL"));
  1490. if (hinstAdvPack)
  1491. {
  1492. REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, "RegInstall");
  1493. if (pfnri)
  1494. {
  1495. hr = pfnri(g_hinst, szSection, NULL);
  1496. }
  1497. FreeLibrary(hinstAdvPack);
  1498. }
  1499. return hr;
  1500. }
  1501. //
  1502. // GOING AWAY: Need to implement setup changes to generate an assemly during setup.
  1503. //
  1504. #if defined(_IA64_)
  1505. #define CC_SIDEBYSIDE TEXT("\\ia64_comctl32_6.0.0.0_0000")
  1506. #elif defined(_X86_)
  1507. #define CC_SIDEBYSIDE TEXT("\\x86_comctl32_6.0.0.0_0000")
  1508. #elif defined(_AMD64_)
  1509. #define CC_SIDEBYSIDE TEXT("\\amd64_comctl32_6.0.0.0_0000")
  1510. #else
  1511. // If this error fires, it means that we've added support for a new platform.
  1512. // Add an appropriate definition for CC_SIDEBYSIDE here.
  1513. #error Unsupported platform - needs definition for CC_SIDEBYSIDE
  1514. #endif
  1515. HRESULT DoFusion()
  1516. {
  1517. #if 0
  1518. // First, Get the module name
  1519. TCHAR szDest[MAX_PATH];
  1520. TCHAR szName[MAX_PATH];
  1521. GetModuleFileName(HINST_THISDLL, szName, ARRAYSIZE(szName));
  1522. GetWindowsDirectory(szDest, ARRAYSIZE(szDest));
  1523. // Make sure %windir%\winsxs exists
  1524. lstrcat(szDest, TEXT("\\winsxs"));
  1525. CreateDirectory(szDest, NULL);
  1526. // Make the x86_comctl32_6.0.0.0_0000 directory
  1527. lstrcat(szDest, CC_SIDEBYSIDE);
  1528. CreateDirectory(szDest, NULL);
  1529. // Copy the file
  1530. lstrcat(szDest, TEXT("\\comctl32.dll"));
  1531. // Copy comctv6.dll to comctl32.dll
  1532. if (!MoveFileEx(szName, szDest, MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_REPLACE_EXISTING))
  1533. return HRESULT_FROM_WIN32(GetLastError());
  1534. // Now generate a manifest
  1535. GetWindowsDirectory(szDest, ARRAYSIZE(szDest));
  1536. lstrcat(szDest, TEXT("\\winsxs") CC_SIDEBYSIDE TEXT("\\comctl32.manifest"));
  1537. // Extract the fusion manifest from the resource.
  1538. SHSquirtManifest(HINST_THISDLL, IDS_CCMANIFEST, szDest);
  1539. #endif
  1540. return S_OK;
  1541. }
  1542. //
  1543. // End going away
  1544. //
  1545. /*----------------------------------------------------------
  1546. Purpose: Install/uninstall user settings
  1547. */
  1548. STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine)
  1549. {
  1550. HRESULT hres = S_OK;
  1551. #ifdef DEBUG
  1552. if (IsFlagSet(g_dwBreakFlags, BF_ONAPIENTER))
  1553. {
  1554. TraceMsg(TF_ALWAYS, "Stopping in DllInstall");
  1555. DEBUG_BREAK;
  1556. }
  1557. #endif
  1558. if (bInstall)
  1559. {
  1560. hres = DoFusion();
  1561. // Delete any old registration entries, then add the new ones.
  1562. // Keep ADVPACK.DLL loaded across multiple calls to RegInstall.
  1563. // (The inf engine doesn't guarantee DelReg/AddReg order, that's
  1564. // why we explicitly unreg and reg here.)
  1565. //
  1566. CallRegInstall("RegDll");
  1567. }
  1568. else
  1569. {
  1570. CallRegInstall("UnregDll");
  1571. }
  1572. return hres;
  1573. }
  1574. //---------------------------------------------------------------------------------------
  1575. void FlipRect(LPRECT prc)
  1576. {
  1577. SWAP(prc->left, prc->top, int);
  1578. SWAP(prc->right, prc->bottom, int);
  1579. }
  1580. //---------------------------------------------------------------------------------------
  1581. //
  1582. // Returns previous window bits.
  1583. DWORD SetWindowBits(HWND hWnd, int iWhich, DWORD dwBits, DWORD dwValue)
  1584. {
  1585. DWORD dwStyle;
  1586. DWORD dwNewStyle;
  1587. dwStyle = GetWindowLong(hWnd, iWhich);
  1588. dwNewStyle = ( dwStyle & ~dwBits ) | (dwValue & dwBits);
  1589. if (dwStyle != dwNewStyle) {
  1590. dwStyle = SetWindowLong(hWnd, iWhich, dwNewStyle);
  1591. }
  1592. return dwStyle;
  1593. }
  1594. //---------------------------------------------------------------------------------------
  1595. BOOL CCDrawEdge(HDC hdc, LPRECT lprc, UINT edge, UINT flags, LPCOLORSCHEME lpclrsc)
  1596. {
  1597. RECT rc, rcD;
  1598. UINT bdrType;
  1599. COLORREF clrTL, clrBR;
  1600. //
  1601. // Enforce monochromicity and flatness
  1602. //
  1603. // if (oemInfo.BitCount == 1)
  1604. // flags |= BF_MONO;
  1605. if (flags & BF_MONO)
  1606. flags |= BF_FLAT;
  1607. CopyRect(&rc, lprc);
  1608. //
  1609. // Draw the border segment(s), and calculate the remaining space as we
  1610. // go.
  1611. //
  1612. if (bdrType = (edge & BDR_OUTER))
  1613. {
  1614. DrawBorder:
  1615. //
  1616. // Get colors. Note the symmetry between raised outer, sunken inner and
  1617. // sunken outer, raised inner.
  1618. //
  1619. if (flags & BF_FLAT)
  1620. {
  1621. if (flags & BF_MONO)
  1622. clrBR = (bdrType & BDR_OUTER) ? g_clrWindowFrame : g_clrWindow;
  1623. else
  1624. clrBR = (bdrType & BDR_OUTER) ? g_clrBtnShadow: g_clrBtnFace;
  1625. clrTL = clrBR;
  1626. }
  1627. else
  1628. {
  1629. // 5 == HILIGHT
  1630. // 4 == LIGHT
  1631. // 3 == FACE
  1632. // 2 == SHADOW
  1633. // 1 == DKSHADOW
  1634. switch (bdrType)
  1635. {
  1636. // +2 above surface
  1637. case BDR_RAISEDOUTER: // 5 : 4
  1638. clrTL = ((flags & BF_SOFT) ? g_clrBtnHighlight : g_clr3DLight);
  1639. clrBR = g_clr3DDkShadow; // 1
  1640. if (lpclrsc) {
  1641. if (lpclrsc->clrBtnHighlight != CLR_DEFAULT)
  1642. clrTL = lpclrsc->clrBtnHighlight;
  1643. if (lpclrsc->clrBtnShadow != CLR_DEFAULT)
  1644. clrBR = lpclrsc->clrBtnShadow;
  1645. }
  1646. break;
  1647. // +1 above surface
  1648. case BDR_RAISEDINNER: // 4 : 5
  1649. clrTL = ((flags & BF_SOFT) ? g_clr3DLight : g_clrBtnHighlight);
  1650. clrBR = g_clrBtnShadow; // 2
  1651. if (lpclrsc) {
  1652. if (lpclrsc->clrBtnHighlight != CLR_DEFAULT)
  1653. clrTL = lpclrsc->clrBtnHighlight;
  1654. if (lpclrsc->clrBtnShadow != CLR_DEFAULT)
  1655. clrBR = lpclrsc->clrBtnShadow;
  1656. }
  1657. break;
  1658. // -1 below surface
  1659. case BDR_SUNKENOUTER: // 1 : 2
  1660. clrTL = ((flags & BF_SOFT) ? g_clr3DDkShadow : g_clrBtnShadow);
  1661. clrBR = g_clrBtnHighlight; // 5
  1662. if (lpclrsc) {
  1663. if (lpclrsc->clrBtnShadow != CLR_DEFAULT)
  1664. clrTL = lpclrsc->clrBtnShadow;
  1665. if (lpclrsc->clrBtnHighlight != CLR_DEFAULT)
  1666. clrBR = lpclrsc->clrBtnHighlight;
  1667. }
  1668. break;
  1669. // -2 below surface
  1670. case BDR_SUNKENINNER: // 2 : 1
  1671. clrTL = ((flags & BF_SOFT) ? g_clrBtnShadow : g_clr3DDkShadow);
  1672. clrBR = g_clr3DLight; // 4
  1673. if (lpclrsc) {
  1674. if (lpclrsc->clrBtnShadow != CLR_DEFAULT)
  1675. clrTL = lpclrsc->clrBtnShadow;
  1676. if (lpclrsc->clrBtnHighlight != CLR_DEFAULT)
  1677. clrBR = lpclrsc->clrBtnHighlight;
  1678. }
  1679. break;
  1680. default:
  1681. return(FALSE);
  1682. }
  1683. }
  1684. //
  1685. // Draw the sides of the border. NOTE THAT THE ALGORITHM FAVORS THE
  1686. // BOTTOM AND RIGHT SIDES, since the light source is assumed to be top
  1687. // left. If we ever decide to let the user set the light source to a
  1688. // particular corner, then change this algorithm.
  1689. //
  1690. // Bottom Right edges
  1691. if (flags & (BF_RIGHT | BF_BOTTOM))
  1692. {
  1693. // Right
  1694. if (flags & BF_RIGHT)
  1695. {
  1696. rc.right -= g_cxBorder;
  1697. // PatBlt(hdc, rc.right, rc.top, g_cxBorder, rc.bottom - rc.top, PATCOPY);
  1698. rcD.left = rc.right;
  1699. rcD.right = rc.right + g_cxBorder;
  1700. rcD.top = rc.top;
  1701. rcD.bottom = rc.bottom;
  1702. FillRectClr(hdc, &rcD, clrBR);
  1703. }
  1704. // Bottom
  1705. if (flags & BF_BOTTOM)
  1706. {
  1707. rc.bottom -= g_cyBorder;
  1708. // PatBlt(hdc, rc.left, rc.bottom, rc.right - rc.left, g_cyBorder, PATCOPY);
  1709. rcD.left = rc.left;
  1710. rcD.right = rc.right;
  1711. rcD.top = rc.bottom;
  1712. rcD.bottom = rc.bottom + g_cyBorder;
  1713. FillRectClr(hdc, &rcD, clrBR);
  1714. }
  1715. }
  1716. // Top Left edges
  1717. if (flags & (BF_TOP | BF_LEFT))
  1718. {
  1719. // Left
  1720. if (flags & BF_LEFT)
  1721. {
  1722. // PatBlt(hdc, rc.left, rc.top, g_cxBorder, rc.bottom - rc.top, PATCOPY);
  1723. rc.left += g_cxBorder;
  1724. rcD.left = rc.left - g_cxBorder;
  1725. rcD.right = rc.left;
  1726. rcD.top = rc.top;
  1727. rcD.bottom = rc.bottom;
  1728. FillRectClr(hdc, &rcD, clrTL);
  1729. }
  1730. // Top
  1731. if (flags & BF_TOP)
  1732. {
  1733. // PatBlt(hdc, rc.left, rc.top, rc.right - rc.left, g_cyBorder, PATCOPY);
  1734. rc.top += g_cyBorder;
  1735. rcD.left = rc.left;
  1736. rcD.right = rc.right;
  1737. rcD.top = rc.top - g_cyBorder;
  1738. rcD.bottom = rc.top;
  1739. FillRectClr(hdc, &rcD, clrTL);
  1740. }
  1741. }
  1742. }
  1743. if (bdrType = (edge & BDR_INNER))
  1744. {
  1745. //
  1746. // Strip this so the next time through, bdrType will be 0.
  1747. // Otherwise, we'll loop forever.
  1748. //
  1749. edge &= ~BDR_INNER;
  1750. goto DrawBorder;
  1751. }
  1752. //
  1753. // Fill the middle & clean up if asked
  1754. //
  1755. if (flags & BF_MIDDLE)
  1756. FillRectClr(hdc, &rc, (flags & BF_MONO) ? g_clrWindow : g_clrBtnFace);
  1757. if (flags & BF_ADJUST)
  1758. CopyRect(lprc, &rc);
  1759. return(TRUE);
  1760. }
  1761. BOOL CCThemeDrawEdge(HTHEME hTheme, HDC hdc, PRECT prc, int iPart, int iState, UINT edge, UINT flags, LPCOLORSCHEME pclrsc)
  1762. {
  1763. RECT rc;
  1764. if (!hTheme)
  1765. return CCDrawEdge(hdc, prc, edge, flags, pclrsc);
  1766. return S_OK == DrawThemeEdge(hTheme, hdc, iPart, iState, prc, edge, flags, &rc);
  1767. }
  1768. //---------------------------------------------------------------------------------------
  1769. //CCInvalidateFrame -- SWP_FRAMECHANGED, w/o all the extra params
  1770. //
  1771. void CCInvalidateFrame(HWND hwnd)
  1772. {
  1773. SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  1774. return;
  1775. }
  1776. //---------------------------------------------------------------------------------------
  1777. // FlipPoint - flip the x and y coordinates of a point
  1778. //
  1779. void FlipPoint(LPPOINT lppt)
  1780. {
  1781. SWAP(lppt->x, lppt->y, int);
  1782. }
  1783. //
  1784. // When we want to turn a tooltip into an infotip, we set its
  1785. // width to 300 "small pixels", where there are 72 small pixels
  1786. // per inch when you are in small fonts mode.
  1787. //
  1788. // Scale this value based on the magnification in effect
  1789. // on the owner's monitor. But never let the tooltip get
  1790. // bigger than 3/4 of the screen.
  1791. //
  1792. void CCSetInfoTipWidth(HWND hwndOwner, HWND hwndToolTips)
  1793. {
  1794. HDC hdc = GetDC(hwndOwner);
  1795. int iWidth = MulDiv(GetDeviceCaps(hdc, LOGPIXELSX), 300, 72);
  1796. int iMaxWidth = GetDeviceCaps(hdc, HORZRES) * 3 / 4;
  1797. SendMessage(hwndToolTips, TTM_SETMAXTIPWIDTH, 0, min(iWidth, iMaxWidth));
  1798. ReleaseDC(hwndOwner, hdc);
  1799. }
  1800. // Mirror a bitmap in a DC (mainly a text object in a DC)
  1801. //
  1802. // [samera]
  1803. //
  1804. void MirrorBitmapInDC( HDC hdc , HBITMAP hbmOrig )
  1805. {
  1806. HDC hdcMem;
  1807. HBITMAP hbm;
  1808. BITMAP bm;
  1809. if( !GetObject( hbmOrig , sizeof(BITMAP) , &bm ))
  1810. return;
  1811. hdcMem = CreateCompatibleDC( hdc );
  1812. if( !hdcMem )
  1813. return;
  1814. hbm = CreateCompatibleBitmap( hdc , bm.bmWidth , bm.bmHeight );
  1815. if( !hbm )
  1816. {
  1817. DeleteDC( hdcMem );
  1818. return;
  1819. }
  1820. //
  1821. // Flip the bitmap
  1822. //
  1823. SelectObject( hdcMem , hbm );
  1824. SET_DC_RTL_MIRRORED(hdcMem);
  1825. BitBlt( hdcMem , 0 , 0 , bm.bmWidth , bm.bmHeight ,
  1826. hdc , 0 , 0 , SRCCOPY );
  1827. SET_DC_LAYOUT(hdcMem,0);
  1828. //
  1829. // The offset by 1 is to solve the off-by-one (in hdcMem) problem. Solved.
  1830. // [samera]
  1831. //
  1832. BitBlt( hdc , 0 , 0 , bm.bmWidth , bm.bmHeight ,
  1833. hdcMem , 0 , 0 , SRCCOPY );
  1834. DeleteDC( hdcMem );
  1835. DeleteObject( hbm );
  1836. return;
  1837. }
  1838. // returns TRUE if handled
  1839. BOOL CCWndProc(CCONTROLINFO* pci, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plres)
  1840. {
  1841. if (uMsg >= CCM_FIRST && uMsg < CCM_LAST)
  1842. {
  1843. LRESULT lres = 0;
  1844. switch (uMsg)
  1845. {
  1846. case CCM_SETUNICODEFORMAT:
  1847. lres = pci->bUnicode;
  1848. pci->bUnicode = BOOLFROMPTR(wParam);
  1849. break;
  1850. case CCM_GETUNICODEFORMAT:
  1851. lres = pci->bUnicode;
  1852. break;
  1853. case CCM_SETVERSION:
  1854. lres = 6;
  1855. break;
  1856. case CCM_GETVERSION:
  1857. lres = 6;
  1858. break;
  1859. case CCM_DPISCALE:
  1860. pci->fDPIAware = (BOOL)wParam;
  1861. lres = 1;
  1862. break;
  1863. }
  1864. ASSERT(plres);
  1865. *plres = lres;
  1866. return TRUE;
  1867. }
  1868. return FALSE;
  1869. }
  1870. // Draws an insertmark.
  1871. void CCDrawInsertMark(HDC hdc, LPRECT prc, BOOL fHorizMode, COLORREF clr)
  1872. {
  1873. HPEN hPnMark = CreatePen(PS_SOLID, 1, clr);
  1874. HPEN hOldPn;
  1875. POINT rgPoint[4];
  1876. if (!hPnMark)
  1877. hPnMark = (HPEN)GetStockObject(BLACK_PEN); // fallback to draw with black pen
  1878. hOldPn = (HPEN)SelectObject(hdc, (HGDIOBJ)hPnMark);
  1879. if ( fHorizMode )
  1880. {
  1881. if (RECTWIDTH(*prc)>INSERTMARKSIZE && RECTHEIGHT(*prc)>3)
  1882. {
  1883. int iXCentre = prc->left + RECTWIDTH(*prc)/2; // make sure we truncate towards prc->left (not towards 0!)
  1884. rgPoint[0].x = iXCentre + 1;
  1885. rgPoint[0].y = prc->top + 2;
  1886. rgPoint[1].x = iXCentre + 3;
  1887. rgPoint[1].y = prc->top;
  1888. rgPoint[2].x = iXCentre - 2;
  1889. rgPoint[2].y = prc->top;
  1890. rgPoint[3].x = iXCentre;
  1891. rgPoint[3].y = prc->top + 2;
  1892. ASSERT(rgPoint[0].x >= prc->left && rgPoint[0].x < prc->right && rgPoint[0].y >= prc->top && rgPoint[0].y < prc->bottom);
  1893. ASSERT(rgPoint[1].x >= prc->left && rgPoint[1].x < prc->right && rgPoint[1].y >= prc->top && rgPoint[1].y < prc->bottom);
  1894. ASSERT(rgPoint[2].x >= prc->left && rgPoint[2].x < prc->right && rgPoint[2].y >= prc->top && rgPoint[2].y < prc->bottom);
  1895. ASSERT(rgPoint[3].x >= prc->left && rgPoint[3].x < prc->right && rgPoint[3].y >= prc->top && rgPoint[3].y < prc->bottom);
  1896. // draw the top bit...
  1897. Polyline( hdc, rgPoint, 4 );
  1898. rgPoint[0].x = iXCentre;
  1899. rgPoint[0].y = prc->top;
  1900. rgPoint[1].x = iXCentre;
  1901. rgPoint[1].y = prc->bottom - 1;
  1902. rgPoint[2].x = iXCentre + 1;
  1903. rgPoint[2].y = prc->bottom - 1;
  1904. rgPoint[3].x = iXCentre + 1;
  1905. rgPoint[3].y = prc->top;
  1906. ASSERT(rgPoint[0].x >= prc->left && rgPoint[0].x < prc->right && rgPoint[0].y >= prc->top && rgPoint[0].y < prc->bottom);
  1907. ASSERT(rgPoint[1].x >= prc->left && rgPoint[1].x < prc->right && rgPoint[1].y >= prc->top && rgPoint[1].y < prc->bottom);
  1908. ASSERT(rgPoint[2].x >= prc->left && rgPoint[2].x < prc->right && rgPoint[2].y >= prc->top && rgPoint[2].y < prc->bottom);
  1909. ASSERT(rgPoint[3].x >= prc->left && rgPoint[3].x < prc->right && rgPoint[3].y >= prc->top && rgPoint[3].y < prc->bottom);
  1910. // draw the middle...
  1911. Polyline( hdc, rgPoint, 4 );
  1912. rgPoint[0].x = iXCentre + 1;
  1913. rgPoint[0].y = prc->bottom - 3;
  1914. rgPoint[1].x = iXCentre + 3;
  1915. rgPoint[1].y = prc->bottom - 1;
  1916. rgPoint[2].x = iXCentre - 2;
  1917. rgPoint[2].y = prc->bottom - 1;
  1918. rgPoint[3].x = iXCentre;
  1919. rgPoint[3].y = prc->bottom - 3;
  1920. ASSERT(rgPoint[0].x >= prc->left && rgPoint[0].x < prc->right && rgPoint[0].y >= prc->top && rgPoint[0].y < prc->bottom);
  1921. ASSERT(rgPoint[1].x >= prc->left && rgPoint[1].x < prc->right && rgPoint[1].y >= prc->top && rgPoint[1].y < prc->bottom);
  1922. ASSERT(rgPoint[2].x >= prc->left && rgPoint[2].x < prc->right && rgPoint[2].y >= prc->top && rgPoint[2].y < prc->bottom);
  1923. ASSERT(rgPoint[3].x >= prc->left && rgPoint[3].x < prc->right && rgPoint[3].y >= prc->top && rgPoint[3].y < prc->bottom);
  1924. // draw the bottom bit...
  1925. Polyline( hdc, rgPoint, 4 );
  1926. }
  1927. }
  1928. else
  1929. {
  1930. if (RECTHEIGHT(*prc)>INSERTMARKSIZE && RECTWIDTH(*prc)>3)
  1931. {
  1932. int iYCentre = prc->top + RECTHEIGHT(*prc)/2; // make sure we truncate towards prc->top (not towards 0!)
  1933. rgPoint[0].x = prc->left + 2;
  1934. rgPoint[0].y = iYCentre;
  1935. rgPoint[1].x = prc->left;
  1936. rgPoint[1].y = iYCentre - 2;
  1937. rgPoint[2].x = prc->left;
  1938. rgPoint[2].y = iYCentre + 3;
  1939. rgPoint[3].x = prc->left + 2;
  1940. rgPoint[3].y = iYCentre + 1;
  1941. ASSERT(rgPoint[0].x >= prc->left && rgPoint[0].x < prc->right && rgPoint[0].y >= prc->top && rgPoint[0].y < prc->bottom);
  1942. ASSERT(rgPoint[1].x >= prc->left && rgPoint[1].x < prc->right && rgPoint[1].y >= prc->top && rgPoint[1].y < prc->bottom);
  1943. ASSERT(rgPoint[2].x >= prc->left && rgPoint[2].x < prc->right && rgPoint[2].y >= prc->top && rgPoint[2].y < prc->bottom);
  1944. ASSERT(rgPoint[3].x >= prc->left && rgPoint[3].x < prc->right && rgPoint[3].y >= prc->top && rgPoint[3].y < prc->bottom);
  1945. // draw the top bit...
  1946. Polyline( hdc, rgPoint, 4 );
  1947. rgPoint[0].x = prc->left;
  1948. rgPoint[0].y = iYCentre;
  1949. rgPoint[1].x = prc->right - 1;
  1950. rgPoint[1].y = iYCentre;
  1951. rgPoint[2].x = prc->right - 1;
  1952. rgPoint[2].y = iYCentre + 1;
  1953. rgPoint[3].x = prc->left;
  1954. rgPoint[3].y = iYCentre + 1;
  1955. ASSERT(rgPoint[0].x >= prc->left && rgPoint[0].x < prc->right && rgPoint[0].y >= prc->top && rgPoint[0].y < prc->bottom);
  1956. ASSERT(rgPoint[1].x >= prc->left && rgPoint[1].x < prc->right && rgPoint[1].y >= prc->top && rgPoint[1].y < prc->bottom);
  1957. ASSERT(rgPoint[2].x >= prc->left && rgPoint[2].x < prc->right && rgPoint[2].y >= prc->top && rgPoint[2].y < prc->bottom);
  1958. ASSERT(rgPoint[3].x >= prc->left && rgPoint[3].x < prc->right && rgPoint[3].y >= prc->top && rgPoint[3].y < prc->bottom);
  1959. // draw the middle...
  1960. Polyline( hdc, rgPoint, 4 );
  1961. rgPoint[0].x = prc->right - 3;
  1962. rgPoint[0].y = iYCentre;
  1963. rgPoint[1].x = prc->right - 1;
  1964. rgPoint[1].y = iYCentre - 2;
  1965. rgPoint[2].x = prc->right - 1;
  1966. rgPoint[2].y = iYCentre + 3;
  1967. rgPoint[3].x = prc->right - 3;
  1968. rgPoint[3].y = iYCentre + 1;
  1969. ASSERT(rgPoint[0].x >= prc->left && rgPoint[0].x < prc->right && rgPoint[0].y >= prc->top && rgPoint[0].y < prc->bottom);
  1970. ASSERT(rgPoint[1].x >= prc->left && rgPoint[1].x < prc->right && rgPoint[1].y >= prc->top && rgPoint[1].y < prc->bottom);
  1971. ASSERT(rgPoint[2].x >= prc->left && rgPoint[2].x < prc->right && rgPoint[2].y >= prc->top && rgPoint[2].y < prc->bottom);
  1972. ASSERT(rgPoint[3].x >= prc->left && rgPoint[3].x < prc->right && rgPoint[3].y >= prc->top && rgPoint[3].y < prc->bottom);
  1973. // draw the bottom bit...
  1974. Polyline( hdc, rgPoint, 4 );
  1975. }
  1976. }
  1977. SelectObject( hdc, hOldPn );
  1978. DeleteObject((HGDIOBJ)hPnMark);
  1979. }
  1980. BOOL CCGetIconSize(LPCCONTROLINFO pCI, HIMAGELIST himl, int* pcx, int* pcy)
  1981. {
  1982. BOOL f = ImageList_GetIconSize(himl, pcx, pcy);
  1983. if (f && pCI->fDPIAware)
  1984. {
  1985. CCDPIScaleX(pcx);
  1986. CCDPIScaleY(pcy);
  1987. }
  1988. return f;
  1989. }
  1990. // The return value tells if the state changed or not (TRUE == change)
  1991. BOOL CCOnUIState(LPCCONTROLINFO pControlInfo,
  1992. UINT uMessage, WPARAM wParam, LPARAM lParam)
  1993. {
  1994. WORD wOldUIState = pControlInfo->wUIState;
  1995. // That's the only message we handle
  1996. if (WM_UPDATEUISTATE == uMessage)
  1997. {
  1998. switch (LOWORD(wParam))
  1999. {
  2000. case UIS_SET:
  2001. pControlInfo->wUIState |= HIWORD(wParam);
  2002. break;
  2003. case UIS_CLEAR:
  2004. pControlInfo->wUIState &= ~(HIWORD(wParam));
  2005. break;
  2006. }
  2007. }
  2008. // These message always need to be passed to DefWindowProc
  2009. return (wOldUIState != pControlInfo->wUIState);
  2010. }
  2011. BOOL CCNotifyNavigationKeyUsage(LPCCONTROLINFO pControlInfo, WORD wFlag)
  2012. {
  2013. BOOL fRet = FALSE;
  2014. // do something only if not already in keyboard mode
  2015. if ((CCGetUIState(pControlInfo) & (UISF_HIDEFOCUS | UISF_HIDEACCEL)) != wFlag)
  2016. {
  2017. SendMessage(pControlInfo->hwndParent, WM_CHANGEUISTATE,
  2018. MAKELONG(UIS_CLEAR, wFlag), 0);
  2019. pControlInfo->wUIState &= ~(wFlag);
  2020. // we did the notify
  2021. fRet = TRUE;
  2022. }
  2023. return fRet;
  2024. }
  2025. BOOL CCGetUIState(LPCCONTROLINFO pControlInfo)
  2026. {
  2027. return pControlInfo->wUIState;
  2028. }
  2029. #ifdef FULL_DEBUG
  2030. void DebugPaintInvalid(HWND hwnd, RECT* prc, HRGN rgn)
  2031. {
  2032. if (GetKeyState(VK_SCROLL) < 0)
  2033. {
  2034. HDC hdc;
  2035. HBRUSH hbrush;
  2036. int bkMode;
  2037. static int s_iclr;
  2038. static COLORREF s_aclr[] =
  2039. {
  2040. RGB(0, 0, 0),
  2041. RGB(255, 0, 0),
  2042. RGB(0, 255, 0),
  2043. RGB(0, 0, 255),
  2044. RGB(255, 255, 0),
  2045. RGB(0, 255, 255),
  2046. RGB(255, 255, 255),
  2047. RGB(255, 0, 255),
  2048. };
  2049. s_iclr = (s_iclr + 1) % ARRAYSIZE(s_aclr);
  2050. hdc = GetDC(hwnd);
  2051. hbrush = CreateHatchBrush(HS_DIAGCROSS, s_aclr[s_iclr]);
  2052. bkMode = SetBkMode(hdc, TRANSPARENT);
  2053. if (rgn)
  2054. {
  2055. FillRgn(hdc, rgn, hbrush);
  2056. }
  2057. else
  2058. {
  2059. RECT rc;
  2060. if (prc == NULL)
  2061. {
  2062. prc = &rc;
  2063. GetClientRect(hwnd, &rc);
  2064. OffsetRect(&rc, -rc.left, -rc.top);
  2065. }
  2066. FillRect(hdc, prc, hbrush);
  2067. }
  2068. DeleteObject((HGDIOBJ)hbrush);
  2069. SetBkMode(hdc, bkMode);
  2070. ReleaseDC(hwnd, hdc);
  2071. if (GetKeyState(VK_SHIFT) < 0)
  2072. Sleep(500);
  2073. else
  2074. Sleep(120);
  2075. }
  2076. }
  2077. void DebugPaintClip(HWND hwnd, HDC hdc)
  2078. {
  2079. if (GetKeyState(VK_SCROLL) < 0)
  2080. {
  2081. HDC hdcH = GetDC(hwnd);
  2082. HRGN hrgn = CreateRectRgn(0, 0, 0, 0);
  2083. GetClipRgn(hdc, hrgn);
  2084. InvertRgn(hdcH, hrgn);
  2085. if (GetKeyState(VK_SHIFT) < 0)
  2086. Sleep(500);
  2087. else
  2088. Sleep(120);
  2089. InvertRgn(hdcH, hrgn);
  2090. DeleteObject(hrgn);
  2091. ReleaseDC(hwnd, hdcH);
  2092. }
  2093. }
  2094. void DebugPaintRect(HDC hdc, PRECT prc)
  2095. {
  2096. if (GetKeyState(VK_SCROLL) < 0)
  2097. {
  2098. HRGN hrgn = CreateRectRgnIndirect(prc);
  2099. InvertRgn(hdc, hrgn);
  2100. if (GetKeyState(VK_SHIFT) < 0)
  2101. Sleep(500);
  2102. else
  2103. Sleep(120);
  2104. InvertRgn(hdc, hrgn);
  2105. DeleteObject(hrgn);
  2106. }
  2107. }
  2108. #endif
  2109. void SHOutlineRectThickness(HDC hdc, const RECT* prc, COLORREF cr, COLORREF crDefault, int cp)
  2110. {
  2111. RECT rc;
  2112. COLORREF clrSave = SetBkColor(hdc, cr == CLR_DEFAULT ? crDefault : cr);
  2113. // See if we overflow the bounding rect
  2114. if (IsRectEmpty(prc))
  2115. {
  2116. return;
  2117. }
  2118. //top
  2119. rc.left = prc->left;
  2120. rc.top = prc->top;
  2121. rc.right = prc->right;
  2122. rc.bottom = prc->top + cp;
  2123. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  2124. //left
  2125. rc.left = prc->left;
  2126. rc.top = prc->top;
  2127. rc.right = prc->left + cp;
  2128. rc.bottom = prc->bottom;
  2129. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  2130. //right
  2131. rc.left = prc->right - cp;
  2132. rc.top = prc->top;
  2133. rc.right = prc->right;
  2134. rc.bottom = prc->bottom;
  2135. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  2136. // bottom
  2137. rc.left = prc->left;
  2138. rc.top = prc->bottom - cp;
  2139. rc.right = prc->right;
  2140. rc.bottom = prc->bottom;
  2141. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  2142. SetBkColor(hdc, clrSave);
  2143. }
  2144. BOOL IsUsingCleartype()
  2145. {
  2146. int iSmoothingType = FE_FONTSMOOTHINGSTANDARD;
  2147. SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &iSmoothingType, 0);
  2148. return FE_FONTSMOOTHINGCLEARTYPE == iSmoothingType;
  2149. }
  2150. BOOL UseMenuSelectionStyle()
  2151. {
  2152. BOOL fUseNewSelectionStyle = FALSE;
  2153. SystemParametersInfo(SPI_GETFLATMENU, 0, (PVOID)&fUseNewSelectionStyle, 0);
  2154. return fUseNewSelectionStyle;
  2155. }
  2156. //#define NO_UXTHEME_PRINTING
  2157. // Gets the bits from the parent for a rect relative to the client
  2158. BOOL CCSendPrintRect(CCONTROLINFO* pci, HDC hdc, RECT* prc)
  2159. {
  2160. #ifndef NO_UXTHEME_PRINTING
  2161. // Call into UxTheme to get the background image. They have hooks to
  2162. // tell us if an app processed this message.
  2163. return (S_OK == DrawThemeParentBackground(pci->hwnd, hdc, prc));
  2164. #else
  2165. HRGN hrgnOld = NULL;
  2166. POINT pt;
  2167. RECT rc;
  2168. if (prc)
  2169. {
  2170. hrgnOld = CreateRectRgn(0,0,0,0);
  2171. // Is there a clipping rgn set on the context already?
  2172. if (GetClipRgn(hdc, hrgnOld) == 0)
  2173. {
  2174. // No, then get rid of the one I just created. NOTE: hrgnOld is NULL meaning we will
  2175. // remove the region later that we set in this next call to SelectClipRgn
  2176. DeleteObject(hrgnOld);
  2177. hrgnOld = NULL;
  2178. }
  2179. IntersectClipRect(hdc, prc->left, prc->top, prc->right, prc->bottom);
  2180. }
  2181. GetWindowRect(pci->hwnd, &rc);
  2182. MapWindowPoints(NULL, pci->hwndParent, (POINT*)&rc, 2);
  2183. GetViewportOrgEx(hdc, &pt);
  2184. SetViewportOrgEx(hdc, pt.x - rc.left, pt.y - rc.top, NULL);
  2185. SendMessage(pci->hwndParent, WM_PRINTCLIENT, (WPARAM)hdc, (LPARAM)PRF_CLIENT);
  2186. SetViewportOrgEx(hdc, pt.x, pt.y, NULL);
  2187. if (hrgnOld)
  2188. {
  2189. SelectClipRgn(hdc, hrgnOld);
  2190. DeleteObject(hrgnOld);
  2191. }
  2192. return TRUE;
  2193. #endif
  2194. }
  2195. // Gets the bits from the parent for the whole control
  2196. BOOL CCSendPrint(CCONTROLINFO* pci, HDC hdc)
  2197. {
  2198. #ifndef NO_UXTHEME_PRINTING
  2199. // Call into UxTheme to get the background image. They have hooks to
  2200. // tell us if an app processed this message.
  2201. return (S_OK == DrawThemeParentBackground(pci->hwnd, hdc, NULL));
  2202. #else
  2203. return CCSendPrintRect(pci, hdc, NULL);
  2204. #endif
  2205. }
  2206. BOOL CCForwardPrint(CCONTROLINFO* pci, HDC hdc)
  2207. {
  2208. #ifndef NO_UXTHEME_PRINTING
  2209. // Call into UxTheme to get the background image. They have hooks to
  2210. // tell us if an app processed this message.
  2211. return (S_OK == DrawThemeParentBackground(pci->hwnd, hdc, NULL));
  2212. #else
  2213. return CCSendPrintRect(pci, hdc, NULL);
  2214. #endif
  2215. }
  2216. BOOL CCShouldAskForBits(CCONTROLINFO* pci, HTHEME hTheme, int iPart, int iState)
  2217. {
  2218. // If the control is transparent, we assume composited.
  2219. return !(pci->dwExStyle & WS_EX_TRANSPARENT) &&
  2220. IsThemeBackgroundPartiallyTransparent(hTheme, iPart, iState);
  2221. }
  2222. BOOL AreAllMonitorsAtLeast(int iBpp)
  2223. {
  2224. DISPLAY_DEVICE DisplayDevice = {sizeof(DISPLAY_DEVICE)};
  2225. BOOL fAreAllMonitorsAtLeast = TRUE;
  2226. int iEnum = 0;
  2227. while (EnumDisplayDevices(NULL, iEnum, &DisplayDevice, 0))
  2228. {
  2229. if (DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
  2230. {
  2231. HDC hdc = CreateDC(NULL, (LPTSTR)DisplayDevice.DeviceName, NULL, NULL);
  2232. if (hdc)
  2233. {
  2234. int iBits = GetDeviceCaps(hdc, BITSPIXEL);
  2235. if (iBits < iBpp)
  2236. fAreAllMonitorsAtLeast = FALSE;
  2237. DeleteDC(hdc);
  2238. }
  2239. }
  2240. ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
  2241. DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
  2242. iEnum++;
  2243. }
  2244. return fAreAllMonitorsAtLeast;
  2245. }
  2246. int CCGetScreenDPI()
  2247. {
  2248. return g_iDPI;
  2249. }
  2250. BOOL CCIsHighDPI()
  2251. {
  2252. return g_fScale;
  2253. }
  2254. int CCScaleX(int x)
  2255. {
  2256. if (g_fScale)
  2257. x = (int)( x * g_dScaleX);
  2258. return x;
  2259. }
  2260. int CCScaleY(int y)
  2261. {
  2262. if (g_fScale)
  2263. y = (int)( y * g_dScaleY);
  2264. return y;
  2265. }
  2266. void CCDPIScaleX(int* x)
  2267. {
  2268. if (g_fScale)
  2269. *x = (int)( *x * g_dScaleX);
  2270. }
  2271. void CCDPIScaleY(int* y)
  2272. {
  2273. if (g_fScale)
  2274. *y = (int)( *y * g_dScaleY);
  2275. }
  2276. void CCDPIUnScaleX(int* x)
  2277. {
  2278. if (g_fScale)
  2279. *x = (int)( *x / g_dScaleX);
  2280. }
  2281. void CCDPIUnScaleY(int* y)
  2282. {
  2283. if (g_fScale)
  2284. *y = (int)( *y / g_dScaleY);
  2285. }
  2286. void CCAdjustForBold(LOGFONT* plf)
  2287. {
  2288. ASSERT(plf);
  2289. plf->lfWeight = FW_BOLD;
  2290. }
  2291. #ifdef DEBUG
  2292. void DumpRgn(ULONGLONG qwFlags, char* trace, HRGN hrgn)
  2293. {
  2294. int iSize = GetRegionData(hrgn, 0, NULL);
  2295. if (iSize > 0)
  2296. {
  2297. RGNDATA* rd = (RGNDATA*)LocalAlloc(LPTR, iSize + sizeof(RGNDATA));
  2298. if (rd)
  2299. {
  2300. DWORD i;
  2301. RECT* prc;
  2302. rd->rdh.dwSize = sizeof(rd->rdh);
  2303. rd->rdh.iType = RDH_RECTANGLES;
  2304. GetRegionData(hrgn, iSize, rd);
  2305. prc = (RECT*)&rd->Buffer;
  2306. for (i = 0; i < rd->rdh.nCount; i++)
  2307. {
  2308. TraceMsg(qwFlags, "%s: %d, %d, %d, %d", trace, prc[i].left, prc[i].top, prc[i].right, prc[i].bottom);
  2309. }
  2310. LocalFree(rd);
  2311. }
  2312. }
  2313. }
  2314. #endif
  2315. HDC CCBeginDoubleBuffer(HDC hdcIn, RECT* prc, CCDBUFFER* pdb)
  2316. {
  2317. HDC hdc = hdcIn;
  2318. ZeroMemory(pdb, sizeof(CCDBUFFER));
  2319. pdb->hPaintDC = hdcIn;
  2320. pdb->rc = *prc;
  2321. pdb->hMemDC = CreateCompatibleDC(hdcIn);
  2322. if (pdb->hMemDC)
  2323. {
  2324. pdb->hMemBm = CreateCompatibleBitmap(hdc, RECTWIDTH(pdb->rc), RECTHEIGHT(pdb->rc));
  2325. if (pdb->hMemBm)
  2326. {
  2327. pdb->hOldBm = (HBITMAP) SelectObject(pdb->hMemDC, pdb->hMemBm);
  2328. // Offset painting to paint in region
  2329. OffsetWindowOrgEx(pdb->hMemDC, pdb->rc.left, pdb->rc.top, NULL);
  2330. pdb->fInitialized = TRUE;
  2331. hdc = pdb->hMemDC;
  2332. }
  2333. else
  2334. {
  2335. DeleteDC(pdb->hMemDC);
  2336. }
  2337. }
  2338. return hdc;
  2339. }
  2340. void CCEndDoubleBuffer(CCDBUFFER* pdb)
  2341. {
  2342. if (pdb->fInitialized)
  2343. {
  2344. BitBlt(pdb->hPaintDC, pdb->rc.left, pdb->rc.top, RECTWIDTH(pdb->rc), RECTHEIGHT(pdb->rc), pdb->hMemDC, pdb->rc.left, pdb->rc.top, SRCCOPY);
  2345. SelectObject(pdb->hMemDC, pdb->hOldBm);
  2346. DeleteObject(pdb->hMemBm);
  2347. DeleteDC(pdb->hMemDC);
  2348. }
  2349. }
  2350. #ifdef FEATURE_FOLLOW_FOCUS_RECT
  2351. HWND g_hwndFocus = NULL;
  2352. void CCLostFocus(HWND hwnd)
  2353. {
  2354. // if (g_hwndFocus)
  2355. // DestroyWindow(g_hwndFocus);
  2356. // g_hwndFocus = NULL;
  2357. }
  2358. HDC CreateLayer(RECT* prc)
  2359. {
  2360. HDC hdc;
  2361. BITMAPINFO bi = {0};
  2362. bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
  2363. bi.bmiHeader.biWidth = RECTWIDTH(*prc);
  2364. bi.bmiHeader.biHeight = RECTHEIGHT(*prc);
  2365. bi.bmiHeader.biPlanes = 1;
  2366. bi.bmiHeader.biBitCount = 32;
  2367. bi.bmiHeader.biCompression = BI_RGB;
  2368. hdc = CreateCompatibleDC(NULL);
  2369. if (hdc)
  2370. {
  2371. ULONG* prgb;
  2372. HBITMAP hbmp = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, (void**)&prgb, NULL, 0);
  2373. if (hbmp)
  2374. {
  2375. int z;
  2376. SIZE sz = {RECTWIDTH(*prc), RECTHEIGHT(*prc)};
  2377. RECT rc = {0, 0, sz.cx, sz.cy};
  2378. int iTotalSize = sz.cx * sz.cy;
  2379. DeleteObject(SelectObject(hdc, hbmp));
  2380. InflateRect(&rc, -2, -2);
  2381. SHOutlineRectThickness(hdc, &rc, RGB(0,0,255), RGB(0,0,255), 1);
  2382. for (z = 0; z < iTotalSize; z++)
  2383. {
  2384. if (((PULONG)prgb)[z] != 0)
  2385. ((PULONG)prgb)[z] = 0xa0000000;
  2386. }
  2387. BlurBitmap(prgb, sz, RGB(0,0,255));
  2388. InflateRect(&rc, -2, -2);
  2389. FillRectClr(hdc, &rc, RGB(0,0,0));
  2390. }
  2391. }
  2392. return hdc;
  2393. }
  2394. typedef struct tagEffect
  2395. {
  2396. HDC hdcImage;
  2397. RECT rcCurrent;
  2398. RECT rcSrc;
  2399. RECT rcDest;
  2400. int iStep;
  2401. } Effect;
  2402. #define EW_SETFOCUS WM_USER+1
  2403. #define EW_LOSTFOCUS WM_USER+2
  2404. void Effect_GenerateRect(Effect* pe, RECT* prc)
  2405. {
  2406. HDC hdcWin = GetDC(g_hwndFocus);
  2407. if (hdcWin)
  2408. {
  2409. BLENDFUNCTION bf = {0};
  2410. POINT pt = {0};
  2411. POINT ptDest = {pe->rcCurrent.left, pe->rcCurrent.top};
  2412. SIZE sz = {RECTWIDTH(*prc), RECTHEIGHT(*prc)};
  2413. if (pe->hdcImage)
  2414. DeleteDC(pe->hdcImage);
  2415. pe->hdcImage = CreateLayer(prc);
  2416. bf.BlendOp = AC_SRC_OVER;
  2417. bf.AlphaFormat = AC_SRC_ALPHA;
  2418. bf.SourceConstantAlpha = 255;
  2419. UpdateLayeredWindow(g_hwndFocus, hdcWin, &ptDest, &sz, pe->hdcImage, &pt, 0, &bf, ULW_ALPHA);
  2420. SetWindowPos(g_hwndFocus, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
  2421. ReleaseDC(g_hwndFocus, hdcWin);
  2422. }
  2423. }
  2424. LRESULT EffectWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2425. {
  2426. Effect* pe = (Effect*)GetWindowLongPtr(hwnd, GWL_USERDATA);
  2427. if ( pe == NULL)
  2428. {
  2429. if (uMsg == WM_NCCREATE)
  2430. {
  2431. pe = LocalAlloc(LPTR, sizeof(Effect));
  2432. SetWindowLong(hwnd, GWL_USERDATA, (LONG)pe);
  2433. }
  2434. if (pe == NULL)
  2435. return 0;
  2436. }
  2437. else switch (uMsg)
  2438. {
  2439. case EW_SETFOCUS:
  2440. {
  2441. RECT* prc = (RECT*)lParam;
  2442. if (IsRectEmpty(&pe->rcCurrent))
  2443. pe->rcSrc = pe->rcCurrent = *prc;
  2444. pe->rcDest = *prc;
  2445. Effect_GenerateRect(pe, prc);
  2446. KillTimer(hwnd, 1);
  2447. pe->rcSrc = pe->rcCurrent;
  2448. pe->iStep = 1;
  2449. SetTimer(hwnd, 2, 5, NULL);
  2450. }
  2451. break;
  2452. case EW_LOSTFOCUS:
  2453. //SetTimer(hwnd, 1, 100, NULL);
  2454. break;
  2455. case WM_TIMER:
  2456. if (wParam == 1)
  2457. {
  2458. DestroyWindow(hwnd);
  2459. g_hwndFocus = NULL;
  2460. }
  2461. else if (wParam == 2)
  2462. {
  2463. BLENDFUNCTION bf = {0};
  2464. POINT pt = {0};
  2465. POINT ptDest;
  2466. SIZE sz;
  2467. if (pe->iStep >= 20 || IsRectEmpty(&pe->rcCurrent) || EqualRect(&pe->rcCurrent, &pe->rcDest))
  2468. {
  2469. pe->rcCurrent = pe->rcDest;
  2470. pe->iStep = 0;
  2471. KillTimer(hwnd, 2);
  2472. }
  2473. else
  2474. {
  2475. pe->rcCurrent.top += (pe->rcDest.top - pe->rcSrc.top) / 20;
  2476. pe->rcCurrent.left += (pe->rcDest.left - pe->rcSrc.left) / 20;
  2477. pe->rcCurrent.right += (pe->rcDest.right - pe->rcSrc.right) / 20;
  2478. pe->rcCurrent.bottom += (pe->rcDest.bottom - pe->rcSrc.bottom) / 20;
  2479. pe->iStep++;
  2480. }
  2481. sz.cx = RECTWIDTH(pe->rcCurrent);
  2482. sz.cy = RECTHEIGHT(pe->rcCurrent);
  2483. ptDest.x = pe->rcCurrent.left;
  2484. ptDest.y = pe->rcCurrent.top;
  2485. Effect_GenerateRect(pe, &pe->rcCurrent);
  2486. }
  2487. break;
  2488. case WM_DESTROY:
  2489. if (pe->hdcImage)
  2490. DeleteDC(pe->hdcImage);
  2491. LocalFree(pe);
  2492. break;
  2493. default:
  2494. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  2495. }
  2496. return 1;
  2497. }
  2498. void CCSetFocus(HWND hwnd, RECT* prc)
  2499. {
  2500. RECT rc;
  2501. if (prc == NULL)
  2502. {
  2503. prc = &rc;
  2504. GetWindowRect(hwnd, &rc);
  2505. }
  2506. InflateRect(prc, 4, 4);
  2507. if (!g_hwndFocus)
  2508. {
  2509. WNDCLASS wc ={0};
  2510. wc.hbrBackground = GetStockObject(BLACK_BRUSH);
  2511. wc.hInstance = HINST_THISDLL;
  2512. wc.lpfnWndProc = EffectWndProc;
  2513. wc.lpszClassName = TEXT("Effect");
  2514. RegisterClass(&wc);
  2515. g_hwndFocus = CreateWindowEx(WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOOLWINDOW, TEXT("Effect"),
  2516. NULL, WS_POPUP, prc->left, prc->top, RECTWIDTH(*prc), RECTHEIGHT(*prc),
  2517. NULL, NULL, HINST_THISDLL, NULL);
  2518. }
  2519. if (g_hwndFocus)
  2520. {
  2521. SendMessage(g_hwndFocus, EW_SETFOCUS, (WPARAM)hwnd, (LPARAM)prc);
  2522. }
  2523. }
  2524. #endif
  2525. BOOL CCDrawNonClientTheme(HTHEME hTheme, HWND hwnd, HRGN hRgnUpdate, HBRUSH hbr, int iPartId, int iStateId)
  2526. {
  2527. BOOL fRet = FALSE;
  2528. HDC hdc;
  2529. DWORD dwFlags = DCX_USESTYLE | DCX_WINDOW | DCX_LOCKWINDOWUPDATE;
  2530. if (hRgnUpdate)
  2531. dwFlags |= DCX_INTERSECTRGN | DCX_NODELETERGN;
  2532. hdc = GetDCEx(hwnd, hRgnUpdate, dwFlags);
  2533. if (hdc)
  2534. {
  2535. RECT rc;
  2536. HRGN hrgn;
  2537. int cxBorder = g_cxBorder, cyBorder = g_cyBorder;
  2538. if (SUCCEEDED(GetThemeInt(hTheme, iPartId, iStateId, TMT_SIZINGBORDERWIDTH, &cxBorder)))
  2539. {
  2540. cyBorder = cxBorder;
  2541. }
  2542. GetWindowRect(hwnd, &rc);
  2543. //
  2544. // Create an update region without the client edge
  2545. // to pass to DefWindowProc
  2546. //
  2547. InflateRect(&rc, -g_cxEdge, -g_cyEdge);
  2548. hrgn = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
  2549. if (hrgn)
  2550. {
  2551. if (hRgnUpdate)
  2552. {
  2553. CombineRgn(hrgn, hRgnUpdate, hrgn, RGN_AND);
  2554. }
  2555. //
  2556. // Zero-origin the rect
  2557. //
  2558. OffsetRect(&rc, -rc.left, -rc.top);
  2559. //
  2560. // clip our drawing to the non-client edge
  2561. //
  2562. OffsetRect(&rc, g_cxEdge, g_cyEdge);
  2563. ExcludeClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
  2564. InflateRect(&rc, g_cxEdge, g_cyEdge);
  2565. DrawThemeBackground(hTheme, hdc, iPartId, iStateId, &rc, 0);
  2566. //
  2567. // Fill with the control's brush first since the ThemeBackground
  2568. // border may not be as thick as the client edge
  2569. //
  2570. if ((cxBorder < g_cxEdge) && (cyBorder < g_cyEdge))
  2571. {
  2572. InflateRect(&rc, cxBorder-g_cxEdge, cyBorder-g_cyEdge);
  2573. FillRect(hdc, &rc, hbr);
  2574. }
  2575. DefWindowProc(hwnd, WM_NCPAINT, (WPARAM)hrgn, 0);
  2576. DeleteObject(hrgn);
  2577. }
  2578. ReleaseDC(hwnd, hdc);
  2579. fRet = TRUE;
  2580. }
  2581. return fRet;
  2582. }
  2583. void FillRectClr(HDC hdc, PRECT prc, COLORREF clr)
  2584. {
  2585. COLORREF clrSave = SetBkColor(hdc, clr);
  2586. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, prc, NULL, 0, NULL);
  2587. SetBkColor(hdc, clrSave);
  2588. }
  2589. void FillPointClr(HDC hdc, POINT* ppt, COLORREF clr)
  2590. {
  2591. RECT rc={ppt->x, ppt->y, ppt->x+1, ppt->y+1};
  2592. COLORREF clrSave = SetBkColor(hdc, clr);
  2593. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  2594. SetBkColor(hdc, clrSave);
  2595. }