graphctl.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /*
  2. * ReactOS Task Manager
  3. *
  4. * graphctl.c
  5. *
  6. * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  21. */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <math.h>
  25. #include <windows.h>
  26. #include <commctrl.h>
  27. #include "graphctl.h"
  28. #include "taskmgr.h"
  29. WNDPROC OldGraphCtrlWndProc;
  30. static void GraphCtrl_Init(TGraphCtrl* this)
  31. {
  32. int i;
  33. this->m_hWnd = 0;
  34. this->m_hParentWnd = 0;
  35. this->m_dcGrid = 0;
  36. this->m_dcPlot = 0;
  37. this->m_bitmapOldGrid = 0;
  38. this->m_bitmapOldPlot = 0;
  39. this->m_bitmapGrid = 0;
  40. this->m_bitmapPlot = 0;
  41. this->m_brushBack = 0;
  42. this->m_penPlot[0] = 0;
  43. this->m_penPlot[1] = 0;
  44. this->m_penPlot[2] = 0;
  45. this->m_penPlot[3] = 0;
  46. /* since plotting is based on a LineTo for each new point
  47. * we need a starting point (i.e. a "previous" point)
  48. * use 0.0 as the default first point.
  49. * these are public member variables, and can be changed outside
  50. * (after construction). Therefore m_dPreviousPosition could be set to
  51. * a more appropriate value prior to the first call to SetPosition.
  52. */
  53. this->m_dPreviousPosition[0] = 0.0;
  54. this->m_dPreviousPosition[1] = 0.0;
  55. this->m_dPreviousPosition[2] = 0.0;
  56. this->m_dPreviousPosition[3] = 0.0;
  57. /* public variable for the number of decimal places on the y axis */
  58. this->m_nYDecimals = 3;
  59. /* set some initial values for the scaling until "SetRange" is called.
  60. * these are protected variables and must be set with SetRange
  61. * in order to ensure that m_dRange is updated accordingly
  62. */
  63. /* m_dLowerLimit = -10.0; */
  64. /* m_dUpperLimit = 10.0; */
  65. this->m_dLowerLimit = 0.0;
  66. this->m_dUpperLimit = 100.0;
  67. this->m_dRange = this->m_dUpperLimit - this->m_dLowerLimit; /* protected member variable */
  68. /* m_nShiftPixels determines how much the plot shifts (in terms of pixels) */
  69. /* with the addition of a new data point */
  70. this->m_nShiftPixels = 4;
  71. this->m_nHalfShiftPixels = this->m_nShiftPixels/2; /* protected */
  72. this->m_nPlotShiftPixels = this->m_nShiftPixels + this->m_nHalfShiftPixels; /* protected */
  73. /* background, grid and data colors */
  74. /* these are public variables and can be set directly */
  75. this->m_crBackColor = RGB( 0, 0, 0); /* see also SetBackgroundColor */
  76. this->m_crGridColor = RGB( 0, 255, 255); /* see also SetGridColor */
  77. this->m_crPlotColor[0] = RGB(255, 255, 255); /* see also SetPlotColor */
  78. this->m_crPlotColor[1] = RGB(100, 255, 255); /* see also SetPlotColor */
  79. this->m_crPlotColor[2] = RGB(255, 100, 255); /* see also SetPlotColor */
  80. this->m_crPlotColor[3] = RGB(255, 255, 100); /* see also SetPlotColor */
  81. /* protected variables */
  82. for (i = 0; i < MAX_PLOTS; i++)
  83. {
  84. this->m_penPlot[i] = CreatePen(PS_SOLID, 0, this->m_crPlotColor[i]);
  85. }
  86. this->m_brushBack = CreateSolidBrush(this->m_crBackColor);
  87. /* public member variables, can be set directly */
  88. strcpy(this->m_strXUnitsString, "Samples"); /* can also be set with SetXUnits */
  89. strcpy(this->m_strYUnitsString, "Y units"); /* can also be set with SetYUnits */
  90. /* protected bitmaps to restore the memory DC's */
  91. this->m_bitmapOldGrid = NULL;
  92. this->m_bitmapOldPlot = NULL;
  93. }
  94. static void GraphCtrl_Resize(TGraphCtrl* this)
  95. {
  96. /* NOTE: Resize automatically gets called during the setup of the control */
  97. GetClientRect(this->m_hWnd, &this->m_rectClient);
  98. /* set some member variables to avoid multiple function calls */
  99. this->m_nClientHeight = this->m_rectClient.bottom - this->m_rectClient.top;/* m_rectClient.Height(); */
  100. this->m_nClientWidth = this->m_rectClient.right - this->m_rectClient.left;/* m_rectClient.Width(); */
  101. /* the "left" coordinate and "width" will be modified in */
  102. /* InvalidateCtrl to be based on the width of the y axis scaling */
  103. SetRect(&this->m_rectPlot, 0, -1, this->m_rectClient.right, this->m_rectClient.bottom);
  104. /* set some member variables to avoid multiple function calls */
  105. this->m_nPlotHeight = this->m_rectPlot.bottom - this->m_rectPlot.top;/* m_rectPlot.Height(); */
  106. this->m_nPlotWidth = this->m_rectPlot.right - this->m_rectPlot.left;/* m_rectPlot.Width(); */
  107. /* set the scaling factor for now, this can be adjusted */
  108. /* in the SetRange functions */
  109. this->m_dVerticalFactor = (double)this->m_nPlotHeight / this->m_dRange;
  110. }
  111. void GraphCtrl_Create(TGraphCtrl* this, HWND hWnd, HWND hParentWnd, UINT nID)
  112. {
  113. GraphCtrl_Init(this);
  114. this->m_hParentWnd = hParentWnd;
  115. this->m_hWnd = hWnd;
  116. GraphCtrl_Resize(this);
  117. }
  118. static void GraphCtrl_InvalidateCtrl(TGraphCtrl* this)
  119. {
  120. /* There is a lot of drawing going on here - particularly in terms of */
  121. /* drawing the grid. Don't panic, this is all being drawn (only once) */
  122. /* to a bitmap. The result is then BitBlt'd to the control whenever needed. */
  123. int i, j;
  124. int nCharacters;
  125. int nTopGridPix, nMidGridPix, nBottomGridPix;
  126. HPEN oldPen;
  127. HPEN solidPen = CreatePen(PS_SOLID, 0, this->m_crGridColor);
  128. /* HFONT axisFont, yUnitFont, oldFont; */
  129. /* char strTemp[50]; */
  130. /* in case we haven't established the memory dc's */
  131. /* CClientDC dc(this); */
  132. HDC dc = GetDC(this->m_hParentWnd);
  133. /* if we don't have one yet, set up a memory dc for the grid */
  134. if (this->m_dcGrid == NULL)
  135. {
  136. this->m_dcGrid = CreateCompatibleDC(dc);
  137. this->m_bitmapGrid = CreateCompatibleBitmap(dc, this->m_nClientWidth, this->m_nClientHeight);
  138. this->m_bitmapOldGrid = SelectObject(this->m_dcGrid, this->m_bitmapGrid);
  139. }
  140. SetBkColor(this->m_dcGrid, this->m_crBackColor);
  141. /* fill the grid background */
  142. FillRect(this->m_dcGrid, &this->m_rectClient, this->m_brushBack);
  143. /* draw the plot rectangle: */
  144. /* determine how wide the y axis scaling values are */
  145. nCharacters = abs((int)log10(fabs(this->m_dUpperLimit)));
  146. nCharacters = max(nCharacters, abs((int)log10(fabs(this->m_dLowerLimit))));
  147. /* add the units digit, decimal point and a minus sign, and an extra space */
  148. /* as well as the number of decimal places to display */
  149. nCharacters = nCharacters + 4 + this->m_nYDecimals;
  150. /* adjust the plot rectangle dimensions */
  151. /* assume 6 pixels per character (this may need to be adjusted) */
  152. /* m_rectPlot.left = m_rectClient.left + 6*(nCharacters); */
  153. this->m_rectPlot.left = this->m_rectClient.left;
  154. this->m_nPlotWidth = this->m_rectPlot.right - this->m_rectPlot.left;/* m_rectPlot.Width(); */
  155. /* draw the plot rectangle */
  156. oldPen = SelectObject(this->m_dcGrid, solidPen);
  157. MoveToEx(this->m_dcGrid, this->m_rectPlot.left, this->m_rectPlot.top, NULL);
  158. LineTo(this->m_dcGrid, this->m_rectPlot.right+1, this->m_rectPlot.top);
  159. LineTo(this->m_dcGrid, this->m_rectPlot.right+1, this->m_rectPlot.bottom+1);
  160. LineTo(this->m_dcGrid, this->m_rectPlot.left, this->m_rectPlot.bottom+1);
  161. /* LineTo(m_dcGrid, m_rectPlot.left, m_rectPlot.top); */
  162. SelectObject(this->m_dcGrid, oldPen);
  163. DeleteObject(solidPen);
  164. /* draw the dotted lines,
  165. * use SetPixel instead of a dotted pen - this allows for a
  166. * finer dotted line and a more "technical" look
  167. */
  168. nMidGridPix = (this->m_rectPlot.top + this->m_rectPlot.bottom)/2;
  169. nTopGridPix = nMidGridPix - this->m_nPlotHeight/4;
  170. nBottomGridPix = nMidGridPix + this->m_nPlotHeight/4;
  171. for (i=this->m_rectPlot.left; i<this->m_rectPlot.right; i+=2)
  172. {
  173. SetPixel(this->m_dcGrid, i, nTopGridPix, this->m_crGridColor);
  174. SetPixel(this->m_dcGrid, i, nMidGridPix, this->m_crGridColor);
  175. SetPixel(this->m_dcGrid, i, nBottomGridPix, this->m_crGridColor);
  176. }
  177. for (i=this->m_rectPlot.left; i<this->m_rectPlot.right; i+=10)
  178. {
  179. for (j=this->m_rectPlot.top; j<this->m_rectPlot.bottom; j+=2)
  180. {
  181. SetPixel(this->m_dcGrid, i, j, this->m_crGridColor);
  182. /* SetPixel(m_dcGrid, i, j, m_crGridColor); */
  183. /* SetPixel(m_dcGrid, i, j, m_crGridColor); */
  184. }
  185. }
  186. /* at this point we are done filling the grid bitmap, */
  187. /* no more drawing to this bitmap is needed until the settings are changed */
  188. /* if we don't have one yet, set up a memory dc for the plot */
  189. if (this->m_dcPlot == NULL)
  190. {
  191. this->m_dcPlot = CreateCompatibleDC(dc);
  192. this->m_bitmapPlot = CreateCompatibleBitmap(dc, this->m_nClientWidth, this->m_nClientHeight);
  193. this->m_bitmapOldPlot = SelectObject(this->m_dcPlot, this->m_bitmapPlot);
  194. }
  195. /* make sure the plot bitmap is cleared */
  196. SetBkColor(this->m_dcPlot, this->m_crBackColor);
  197. FillRect(this->m_dcPlot, &this->m_rectClient, this->m_brushBack);
  198. /* finally, force the plot area to redraw */
  199. InvalidateRect(this->m_hParentWnd, &this->m_rectClient, TRUE);
  200. ReleaseDC(this->m_hParentWnd, dc);
  201. }
  202. void GraphCtrl_SetRange(TGraphCtrl* this, double dLower, double dUpper, int nDecimalPlaces)
  203. {
  204. /* ASSERT(dUpper > dLower); */
  205. this->m_dLowerLimit = dLower;
  206. this->m_dUpperLimit = dUpper;
  207. this->m_nYDecimals = nDecimalPlaces;
  208. this->m_dRange = this->m_dUpperLimit - this->m_dLowerLimit;
  209. this->m_dVerticalFactor = (double)this->m_nPlotHeight / this->m_dRange;
  210. /* clear out the existing garbage, re-start with a clean plot */
  211. GraphCtrl_InvalidateCtrl(this);
  212. }
  213. void GraphCtrl_SetGridColor(TGraphCtrl* this, COLORREF color)
  214. {
  215. this->m_crGridColor = color;
  216. /* clear out the existing garbage, re-start with a clean plot */
  217. GraphCtrl_InvalidateCtrl(this);
  218. }
  219. void GraphCtrl_SetPlotColor(TGraphCtrl* this, int plot, COLORREF color)
  220. {
  221. this->m_crPlotColor[plot] = color;
  222. DeleteObject(this->m_penPlot[plot]);
  223. this->m_penPlot[plot] = CreatePen(PS_SOLID, 0, this->m_crPlotColor[plot]);
  224. /* clear out the existing garbage, re-start with a clean plot */
  225. GraphCtrl_InvalidateCtrl(this);
  226. }
  227. void GraphCtrl_SetBackgroundColor(TGraphCtrl* this, COLORREF color)
  228. {
  229. this->m_crBackColor = color;
  230. DeleteObject(this->m_brushBack);
  231. this->m_brushBack = CreateSolidBrush(this->m_crBackColor);
  232. /* clear out the existing garbage, re-start with a clean plot */
  233. GraphCtrl_InvalidateCtrl(this);
  234. }
  235. static void GraphCtrl_DrawPoint(TGraphCtrl* this)
  236. {
  237. /* this does the work of "scrolling" the plot to the left
  238. * and appending a new data point all of the plotting is
  239. * directed to the memory based bitmap associated with m_dcPlot
  240. * the will subsequently be BitBlt'd to the client in Paint
  241. */
  242. int currX, prevX, currY, prevY;
  243. HPEN oldPen;
  244. RECT rectCleanUp;
  245. int i;
  246. if (this->m_dcPlot != NULL)
  247. {
  248. /* shift the plot by BitBlt'ing it to itself
  249. * note: the m_dcPlot covers the entire client
  250. * but we only shift bitmap that is the size
  251. * of the plot rectangle
  252. * grab the right side of the plot (excluding m_nShiftPixels on the left)
  253. * move this grabbed bitmap to the left by m_nShiftPixels
  254. */
  255. BitBlt(this->m_dcPlot, this->m_rectPlot.left, this->m_rectPlot.top+1,
  256. this->m_nPlotWidth, this->m_nPlotHeight, this->m_dcPlot,
  257. this->m_rectPlot.left+this->m_nShiftPixels, this->m_rectPlot.top+1,
  258. SRCCOPY);
  259. /* establish a rectangle over the right side of plot */
  260. /* which now needs to be cleaned up prior to adding the new point */
  261. rectCleanUp = this->m_rectPlot;
  262. rectCleanUp.left = rectCleanUp.right - this->m_nShiftPixels;
  263. /* fill the cleanup area with the background */
  264. FillRect(this->m_dcPlot, &rectCleanUp, this->m_brushBack);
  265. /* draw the next line segment */
  266. for (i = 0; i < MAX_PLOTS; i++)
  267. {
  268. /* grab the plotting pen */
  269. oldPen = SelectObject(this->m_dcPlot, this->m_penPlot[i]);
  270. /* move to the previous point */
  271. prevX = this->m_rectPlot.right-this->m_nPlotShiftPixels;
  272. prevY = this->m_rectPlot.bottom -
  273. (int)((this->m_dPreviousPosition[i] - this->m_dLowerLimit) * this->m_dVerticalFactor);
  274. MoveToEx(this->m_dcPlot, prevX, prevY, NULL);
  275. /* draw to the current point */
  276. currX = this->m_rectPlot.right-this->m_nHalfShiftPixels;
  277. currY = this->m_rectPlot.bottom -
  278. (int)((this->m_dCurrentPosition[i] - this->m_dLowerLimit) * this->m_dVerticalFactor);
  279. LineTo(this->m_dcPlot, currX, currY);
  280. /* Restore the pen */
  281. SelectObject(this->m_dcPlot, oldPen);
  282. /* if the data leaks over the upper or lower plot boundaries
  283. * fill the upper and lower leakage with the background
  284. * this will facilitate clipping on an as needed basis
  285. * as opposed to always calling IntersectClipRect
  286. */
  287. if ((prevY <= this->m_rectPlot.top) || (currY <= this->m_rectPlot.top))
  288. {
  289. RECT rc;
  290. SetRect(&rc, prevX, this->m_rectClient.top, currX + 1, this->m_rectPlot.top + 1);
  291. FillRect(this->m_dcPlot, &rc, this->m_brushBack);
  292. }
  293. if ((prevY >= this->m_rectPlot.bottom) || (currY >= this->m_rectPlot.bottom))
  294. {
  295. RECT rc;
  296. SetRect(&rc, prevX, this->m_rectPlot.bottom + 1, currX + 1,
  297. this->m_rectClient.bottom + 1);
  298. /* RECT rc(prevX, m_rectPlot.bottom+1, currX+1, m_rectClient.bottom+1); */
  299. FillRect(this->m_dcPlot, &rc, this->m_brushBack);
  300. }
  301. /* store the current point for connection to the next point */
  302. this->m_dPreviousPosition[i] = this->m_dCurrentPosition[i];
  303. }
  304. }
  305. }
  306. double GraphCtrl_AppendPoint(TGraphCtrl* this,
  307. double dNewPoint0, double dNewPoint1,
  308. double dNewPoint2, double dNewPoint3)
  309. {
  310. /* append a data point to the plot & return the previous point */
  311. double dPrevious;
  312. dPrevious = this->m_dCurrentPosition[0];
  313. this->m_dCurrentPosition[0] = dNewPoint0;
  314. this->m_dCurrentPosition[1] = dNewPoint1;
  315. this->m_dCurrentPosition[2] = dNewPoint2;
  316. this->m_dCurrentPosition[3] = dNewPoint3;
  317. GraphCtrl_DrawPoint(this);
  318. /* Invalidate(); */
  319. return dPrevious;
  320. }
  321. static void GraphCtrl_Paint(TGraphCtrl* this, HWND hWnd, HDC dc)
  322. {
  323. HDC memDC;
  324. HBITMAP memBitmap;
  325. HBITMAP oldBitmap; /* bitmap originally found in CMemDC */
  326. /* no real plotting work is performed here, */
  327. /* just putting the existing bitmaps on the client */
  328. /* to avoid flicker, establish a memory dc, draw to it */
  329. /* and then BitBlt it to the client */
  330. memDC = CreateCompatibleDC(dc);
  331. memBitmap = CreateCompatibleBitmap(dc, this->m_nClientWidth, this->m_nClientHeight);
  332. oldBitmap = SelectObject(memDC, memBitmap);
  333. if (memDC != NULL)
  334. {
  335. /* first drop the grid on the memory dc */
  336. BitBlt(memDC, 0, 0, this->m_nClientWidth, this->m_nClientHeight, this->m_dcGrid, 0, 0, SRCCOPY);
  337. /* now add the plot on top as a "pattern" via SRCPAINT. */
  338. /* works well with dark background and a light plot */
  339. BitBlt(memDC, 0, 0, this->m_nClientWidth, this->m_nClientHeight, this->m_dcPlot, 0, 0, SRCPAINT); /* SRCPAINT */
  340. /* finally send the result to the display */
  341. BitBlt(dc, 0, 0, this->m_nClientWidth, this->m_nClientHeight, memDC, 0, 0, SRCCOPY);
  342. }
  343. SelectObject(memDC, oldBitmap);
  344. DeleteObject(memBitmap);
  345. DeleteDC(memDC);
  346. }
  347. extern TGraphCtrl PerformancePageCpuUsageHistoryGraph;
  348. extern TGraphCtrl PerformancePageMemUsageHistoryGraph;
  349. extern HWND hPerformancePageCpuUsageHistoryGraph;
  350. extern HWND hPerformancePageMemUsageHistoryGraph;
  351. INT_PTR CALLBACK
  352. GraphCtrl_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  353. {
  354. RECT rcClient;
  355. HDC hdc;
  356. PAINTSTRUCT ps;
  357. switch (message)
  358. {
  359. case WM_ERASEBKGND:
  360. return TRUE;
  361. /*
  362. * Filter out mouse & keyboard messages
  363. */
  364. /* case WM_APPCOMMAND: */
  365. case WM_CAPTURECHANGED:
  366. case WM_LBUTTONDBLCLK:
  367. case WM_LBUTTONDOWN:
  368. case WM_LBUTTONUP:
  369. case WM_MBUTTONDBLCLK:
  370. case WM_MBUTTONDOWN:
  371. case WM_MBUTTONUP:
  372. case WM_MOUSEACTIVATE:
  373. case WM_MOUSEHOVER:
  374. case WM_MOUSELEAVE:
  375. case WM_MOUSEMOVE:
  376. /* case WM_MOUSEWHEEL: */
  377. case WM_NCHITTEST:
  378. case WM_NCLBUTTONDBLCLK:
  379. case WM_NCLBUTTONDOWN:
  380. case WM_NCLBUTTONUP:
  381. case WM_NCMBUTTONDBLCLK:
  382. case WM_NCMBUTTONDOWN:
  383. case WM_NCMBUTTONUP:
  384. /* case WM_NCMOUSEHOVER: */
  385. /* case WM_NCMOUSELEAVE: */
  386. case WM_NCMOUSEMOVE:
  387. case WM_NCRBUTTONDBLCLK:
  388. case WM_NCRBUTTONDOWN:
  389. case WM_NCRBUTTONUP:
  390. /* case WM_NCXBUTTONDBLCLK: */
  391. /* case WM_NCXBUTTONDOWN: */
  392. /* case WM_NCXBUTTONUP: */
  393. case WM_RBUTTONDBLCLK:
  394. case WM_RBUTTONDOWN:
  395. case WM_RBUTTONUP:
  396. /* case WM_XBUTTONDBLCLK: */
  397. /* case WM_XBUTTONDOWN: */
  398. /* case WM_XBUTTONUP: */
  399. case WM_ACTIVATE:
  400. case WM_CHAR:
  401. case WM_DEADCHAR:
  402. case WM_GETHOTKEY:
  403. case WM_HOTKEY:
  404. case WM_KEYDOWN:
  405. case WM_KEYUP:
  406. case WM_KILLFOCUS:
  407. case WM_SETFOCUS:
  408. case WM_SETHOTKEY:
  409. case WM_SYSCHAR:
  410. case WM_SYSDEADCHAR:
  411. case WM_SYSKEYDOWN:
  412. case WM_SYSKEYUP:
  413. return 0;
  414. case WM_NCCALCSIZE:
  415. return 0;
  416. case WM_SIZE:
  417. if (hWnd == hPerformancePageMemUsageHistoryGraph)
  418. {
  419. GraphCtrl_Resize(&PerformancePageMemUsageHistoryGraph);
  420. GraphCtrl_InvalidateCtrl(&PerformancePageMemUsageHistoryGraph);
  421. }
  422. if (hWnd == hPerformancePageCpuUsageHistoryGraph)
  423. {
  424. GraphCtrl_Resize(&PerformancePageCpuUsageHistoryGraph);
  425. GraphCtrl_InvalidateCtrl(&PerformancePageCpuUsageHistoryGraph);
  426. }
  427. return 0;
  428. case WM_PAINT:
  429. hdc = BeginPaint(hWnd, &ps);
  430. GetClientRect(hWnd, &rcClient);
  431. if (hWnd == hPerformancePageMemUsageHistoryGraph)
  432. GraphCtrl_Paint(&PerformancePageMemUsageHistoryGraph, hWnd, hdc);
  433. if (hWnd == hPerformancePageCpuUsageHistoryGraph)
  434. GraphCtrl_Paint(&PerformancePageCpuUsageHistoryGraph, hWnd, hdc);
  435. EndPaint(hWnd, &ps);
  436. return 0;
  437. }
  438. /*
  439. * We pass on all non-handled messages
  440. */
  441. return CallWindowProcW(OldGraphCtrlWndProc, hWnd, message, wParam, lParam);
  442. }