graph.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /*
  2. * ReactOS Task Manager
  3. *
  4. * graph.c
  5. *
  6. * Copyright (C) 1999 - 2001 Brian Palmer <brianp@reactos.org>
  7. * Copyright (C) 2008 Vladimir Pankratov
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation; either
  12. * version 2.1 of the License, or (at your option) any later version.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <windows.h>
  26. #include <commctrl.h>
  27. #include <shlwapi.h>
  28. #include <winnt.h>
  29. #include "taskmgr.h"
  30. #include "perfdata.h"
  31. #define BRIGHT_GREEN RGB(0, 255, 0)
  32. #define DARK_GREEN RGB(0, 130, 0)
  33. #define RED RGB(255, 0, 0)
  34. WNDPROC OldGraphWndProc;
  35. static void Graph_DrawCpuUsageGraph(HDC hDC, HWND hWnd)
  36. {
  37. RECT rcClient;
  38. RECT rcBarLeft;
  39. RECT rcBarRight;
  40. RECT rcText;
  41. WCHAR Text[256];
  42. ULONG CpuUsage;
  43. ULONG CpuKernelUsage;
  44. int nBars;
  45. int nBarsUsed;
  46. /* Bottom bars that are "used", i.e. are bright green, representing used cpu time */
  47. int nBarsUsedKernel;
  48. /* Bottom bars that are "used", i.e. are bright green, representing used cpu kernel time */
  49. int nBarsFree;
  50. /* Top bars that are "unused", i.e. are dark green, representing free cpu time */
  51. int i;
  52. static const WCHAR wszFormatI[] = {'%','d','%','%',0};
  53. static const WCHAR wszFormatII[] = {' ',' ','%','d','%','%',0};
  54. static const WCHAR wszFormatIII[] = {' ','%','d','%','%',0};
  55. /*
  56. * Get the client area rectangle
  57. */
  58. GetClientRect(hWnd, &rcClient);
  59. /*
  60. * Fill it with blackness
  61. */
  62. FillSolidRect(hDC, &rcClient, RGB(0, 0, 0));
  63. /*
  64. * Get the CPU usage
  65. */
  66. CpuUsage = PerfDataGetProcessorUsage();
  67. CpuKernelUsage = PerfDataGetProcessorSystemUsage();
  68. /*
  69. * Check and see how many digits it will take
  70. * so we get the indentation right every time.
  71. */
  72. if (CpuUsage == 100)
  73. {
  74. swprintf(Text, ARRAY_SIZE(Text), wszFormatI, (int)CpuUsage);
  75. }
  76. else if (CpuUsage < 10)
  77. {
  78. swprintf(Text, ARRAY_SIZE(Text), wszFormatII, (int)CpuUsage);
  79. }
  80. else
  81. {
  82. swprintf(Text, ARRAY_SIZE(Text), wszFormatIII, (int)CpuUsage);
  83. }
  84. /*
  85. * Draw the font text onto the graph
  86. * The bottom 20 pixels are reserved for the text
  87. */
  88. CopyRect(&rcText, &rcClient);
  89. rcText.top = rcText.bottom - 19;
  90. SetTextColor(hDC, BRIGHT_GREEN);
  91. DrawTextW(hDC, Text, -1, &rcText, DT_CENTER);
  92. /*
  93. * Now we have to draw the graph
  94. * So first find out how many bars we can fit
  95. */
  96. nBars = ((rcClient.bottom - rcClient.top) - 25) / 3;
  97. nBarsUsed = (nBars * CpuUsage) / 100;
  98. if ((CpuUsage) && (nBarsUsed == 0))
  99. {
  100. nBarsUsed = 1;
  101. }
  102. nBarsFree = nBars - nBarsUsed;
  103. if (TaskManagerSettings.ShowKernelTimes)
  104. {
  105. nBarsUsedKernel = ((nBars * 2) * CpuKernelUsage) / 100;
  106. nBarsUsed -= (nBarsUsedKernel / 2);
  107. }
  108. else
  109. {
  110. nBarsUsedKernel = 0;
  111. }
  112. /*
  113. * Now draw the bar graph
  114. */
  115. rcBarLeft.left = ((rcClient.right - rcClient.left) - 33) / 2;
  116. rcBarLeft.right = rcBarLeft.left + 16;
  117. rcBarRight.left = rcBarLeft.left + 17;
  118. rcBarRight.right = rcBarLeft.right + 17;
  119. rcBarLeft.top = rcBarRight.top = 5;
  120. rcBarLeft.bottom = rcBarRight.bottom = 7;
  121. if (nBarsUsed < 0) nBarsUsed = 0;
  122. if (nBarsUsed > nBars) nBarsUsed = nBars;
  123. if (nBarsFree < 0) nBarsFree = 0;
  124. if (nBarsFree > nBars) nBarsFree = nBars;
  125. if (nBarsUsedKernel < 0) nBarsUsedKernel = 0;
  126. if (nBarsUsedKernel > nBars) nBarsUsedKernel = nBars;
  127. /*
  128. * Draw the "free" bars
  129. */
  130. for (i=0; i<nBarsFree; i++)
  131. {
  132. FillSolidRect(hDC, &rcBarLeft, DARK_GREEN);
  133. FillSolidRect(hDC, &rcBarRight, DARK_GREEN);
  134. rcBarLeft.top += 3;
  135. rcBarLeft.bottom += 3;
  136. rcBarRight.top += 3;
  137. rcBarRight.bottom += 3;
  138. }
  139. /*
  140. * Draw the "used" bars
  141. */
  142. for (i=0; i<nBarsUsed; i++)
  143. {
  144. if (nBarsUsed > 5000) nBarsUsed = 5000;
  145. FillSolidRect(hDC, &rcBarLeft, BRIGHT_GREEN);
  146. FillSolidRect(hDC, &rcBarRight, BRIGHT_GREEN);
  147. rcBarLeft.top += 3;
  148. rcBarLeft.bottom += 3;
  149. rcBarRight.top += 3;
  150. rcBarRight.bottom += 3;
  151. }
  152. /*
  153. * Draw the "used" kernel bars
  154. */
  155. rcBarLeft.bottom--;
  156. rcBarRight.bottom--;
  157. if (nBarsUsedKernel && nBarsUsedKernel % 2)
  158. {
  159. rcBarLeft.top -= 2;
  160. rcBarLeft.bottom -= 2;
  161. rcBarRight.top -= 2;
  162. rcBarRight.bottom -= 2;
  163. FillSolidRect(hDC, &rcBarLeft, RED);
  164. FillSolidRect(hDC, &rcBarRight, RED);
  165. rcBarLeft.top += 2;
  166. rcBarLeft.bottom += 2;
  167. rcBarRight.top += 2;
  168. rcBarRight.bottom += 2;
  169. nBarsUsedKernel--;
  170. }
  171. for (i=0; i<nBarsUsedKernel; i++)
  172. {
  173. if (nBarsUsedKernel > 5000) nBarsUsedKernel = 5000;
  174. FillSolidRect(hDC, &rcBarLeft, RED);
  175. FillSolidRect(hDC, &rcBarRight, RED);
  176. rcBarLeft.top++;
  177. rcBarLeft.bottom++;
  178. rcBarRight.top++;
  179. rcBarRight.bottom++;
  180. if (i % 2)
  181. {
  182. rcBarLeft.top++;
  183. rcBarLeft.bottom++;
  184. rcBarRight.top++;
  185. rcBarRight.bottom++;
  186. }
  187. }
  188. }
  189. static void Graph_DrawMemUsageGraph(HDC hDC, HWND hWnd)
  190. {
  191. RECT rcClient;
  192. RECT rcBarLeft;
  193. RECT rcBarRight;
  194. RECT rcText;
  195. WCHAR Text[256];
  196. ULONGLONG CommitChargeTotal;
  197. ULONGLONG CommitChargeLimit;
  198. int nBars;
  199. int nBarsUsed = 0;
  200. /* Bottom bars that are "used", i.e. are bright green, representing used memory */
  201. int nBarsFree;
  202. /* Top bars that are "unused", i.e. are dark green, representing free memory */
  203. int i;
  204. /*
  205. * Get the client area rectangle
  206. */
  207. GetClientRect(hWnd, &rcClient);
  208. /*
  209. * Fill it with blackness
  210. */
  211. FillSolidRect(hDC, &rcClient, RGB(0, 0, 0));
  212. /*
  213. * Get the memory usage
  214. */
  215. CommitChargeTotal = (ULONGLONG)PerfDataGetCommitChargeTotalK();
  216. CommitChargeLimit = (ULONGLONG)PerfDataGetCommitChargeLimitK();
  217. if (CommitChargeTotal < 1024)
  218. StrFormatKBSizeW(CommitChargeTotal, Text, ARRAY_SIZE(Text));
  219. else
  220. StrFormatByteSizeW(CommitChargeTotal, Text, ARRAY_SIZE(Text));
  221. /*
  222. * Draw the font text onto the graph
  223. * The bottom 20 pixels are reserved for the text
  224. */
  225. CopyRect(&rcText, &rcClient);
  226. rcText.top = rcText.bottom - 19;
  227. SetTextColor(hDC, BRIGHT_GREEN);
  228. DrawTextW(hDC, Text, -1, &rcText, DT_CENTER);
  229. /*
  230. * Now we have to draw the graph
  231. * So first find out how many bars we can fit
  232. */
  233. nBars = ((rcClient.bottom - rcClient.top) - 25) / 3;
  234. if (CommitChargeLimit)
  235. nBarsUsed = (nBars * (int)((CommitChargeTotal * 100) / CommitChargeLimit)) / 100;
  236. nBarsFree = nBars - nBarsUsed;
  237. if (nBarsUsed < 0) nBarsUsed = 0;
  238. if (nBarsUsed > nBars) nBarsUsed = nBars;
  239. if (nBarsFree < 0) nBarsFree = 0;
  240. if (nBarsFree > nBars) nBarsFree = nBars;
  241. /*
  242. * Now draw the bar graph
  243. */
  244. rcBarLeft.left = ((rcClient.right - rcClient.left) - 33) / 2;
  245. rcBarLeft.right = rcBarLeft.left + 16;
  246. rcBarRight.left = rcBarLeft.left + 17;
  247. rcBarRight.right = rcBarLeft.right + 17;
  248. rcBarLeft.top = rcBarRight.top = 5;
  249. rcBarLeft.bottom = rcBarRight.bottom = 7;
  250. /*
  251. * Draw the "free" bars
  252. */
  253. for (i=0; i<nBarsFree; i++)
  254. {
  255. FillSolidRect(hDC, &rcBarLeft, DARK_GREEN);
  256. FillSolidRect(hDC, &rcBarRight, DARK_GREEN);
  257. rcBarLeft.top += 3;
  258. rcBarLeft.bottom += 3;
  259. rcBarRight.top += 3;
  260. rcBarRight.bottom += 3;
  261. }
  262. /*
  263. * Draw the "used" bars
  264. */
  265. for (i=0; i<nBarsUsed; i++)
  266. {
  267. FillSolidRect(hDC, &rcBarLeft, BRIGHT_GREEN);
  268. FillSolidRect(hDC, &rcBarRight, BRIGHT_GREEN);
  269. rcBarLeft.top += 3;
  270. rcBarLeft.bottom += 3;
  271. rcBarRight.top += 3;
  272. rcBarRight.bottom += 3;
  273. }
  274. }
  275. static void Graph_DrawMemUsageHistoryGraph(HDC hDC, HWND hWnd)
  276. {
  277. RECT rcClient;
  278. int i;
  279. static int offset = 0;
  280. if (offset++ >= 10)
  281. offset = 0;
  282. /*
  283. * Get the client area rectangle
  284. */
  285. GetClientRect(hWnd, &rcClient);
  286. /*
  287. * Fill it with blackness
  288. */
  289. FillSolidRect(hDC, &rcClient, RGB(0, 0, 0));
  290. /*
  291. * Draw the graph background
  292. *
  293. * Draw the horizontal bars
  294. */
  295. for (i=0; i<rcClient.bottom; i++)
  296. {
  297. if ((i % 11) == 0)
  298. {
  299. /* FillSolidRect2(hDC, 0, i, rcClient.right, 1, DARK_GREEN); */
  300. }
  301. }
  302. /*
  303. * Draw the vertical bars
  304. */
  305. for (i=11; i<rcClient.right + offset; i++)
  306. {
  307. if ((i % 11) == 0)
  308. {
  309. /* FillSolidRect2(hDC, i - offset, 0, 1, rcClient.bottom, DARK_GREEN); */
  310. }
  311. }
  312. /*
  313. * Draw the memory usage
  314. */
  315. for (i=rcClient.right; i>=0; i--)
  316. {
  317. }
  318. }
  319. INT_PTR CALLBACK
  320. Graph_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  321. {
  322. HDC hdc;
  323. PAINTSTRUCT ps;
  324. LONG WindowId;
  325. switch (message)
  326. {
  327. case WM_ERASEBKGND:
  328. return TRUE;
  329. /*
  330. * Filter out mouse & keyboard messages
  331. */
  332. /* case WM_APPCOMMAND: */
  333. case WM_CAPTURECHANGED:
  334. case WM_LBUTTONDBLCLK:
  335. case WM_LBUTTONDOWN:
  336. case WM_LBUTTONUP:
  337. case WM_MBUTTONDBLCLK:
  338. case WM_MBUTTONDOWN:
  339. case WM_MBUTTONUP:
  340. case WM_MOUSEACTIVATE:
  341. case WM_MOUSEHOVER:
  342. case WM_MOUSELEAVE:
  343. case WM_MOUSEMOVE:
  344. /* case WM_MOUSEWHEEL: */
  345. case WM_NCHITTEST:
  346. case WM_NCLBUTTONDBLCLK:
  347. case WM_NCLBUTTONDOWN:
  348. case WM_NCLBUTTONUP:
  349. case WM_NCMBUTTONDBLCLK:
  350. case WM_NCMBUTTONDOWN:
  351. case WM_NCMBUTTONUP:
  352. /* case WM_NCMOUSEHOVER: */
  353. /* case WM_NCMOUSELEAVE: */
  354. case WM_NCMOUSEMOVE:
  355. case WM_NCRBUTTONDBLCLK:
  356. case WM_NCRBUTTONDOWN:
  357. case WM_NCRBUTTONUP:
  358. /* case WM_NCXBUTTONDBLCLK: */
  359. /* case WM_NCXBUTTONDOWN: */
  360. /* case WM_NCXBUTTONUP: */
  361. case WM_RBUTTONDBLCLK:
  362. case WM_RBUTTONDOWN:
  363. case WM_RBUTTONUP:
  364. /* case WM_XBUTTONDBLCLK: */
  365. /* case WM_XBUTTONDOWN: */
  366. /* case WM_XBUTTONUP: */
  367. case WM_ACTIVATE:
  368. case WM_CHAR:
  369. case WM_DEADCHAR:
  370. case WM_GETHOTKEY:
  371. case WM_HOTKEY:
  372. case WM_KEYDOWN:
  373. case WM_KEYUP:
  374. case WM_KILLFOCUS:
  375. case WM_SETFOCUS:
  376. case WM_SETHOTKEY:
  377. case WM_SYSCHAR:
  378. case WM_SYSDEADCHAR:
  379. case WM_SYSKEYDOWN:
  380. case WM_SYSKEYUP:
  381. case WM_NCCALCSIZE:
  382. return 0;
  383. case WM_PAINT:
  384. hdc = BeginPaint(hWnd, &ps);
  385. WindowId = GetWindowLongPtrW(hWnd, GWLP_ID);
  386. switch (WindowId)
  387. {
  388. case IDC_CPU_USAGE_GRAPH:
  389. Graph_DrawCpuUsageGraph(hdc, hWnd);
  390. break;
  391. case IDC_MEM_USAGE_GRAPH:
  392. Graph_DrawMemUsageGraph(hdc, hWnd);
  393. break;
  394. case IDC_MEM_USAGE_HISTORY_GRAPH:
  395. Graph_DrawMemUsageHistoryGraph(hdc, hWnd);
  396. break;
  397. }
  398. EndPaint(hWnd, &ps);
  399. return 0;
  400. }
  401. /*
  402. * We pass on all non-handled messages
  403. */
  404. return CallWindowProcW(OldGraphWndProc, hWnd, message, wParam, lParam);
  405. }