1 /*
2 * PROJECT: ReactOS Task Manager
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Graph Plotting controls.
5 * COPYRIGHT: Copyright 2002 Robert Dickenson <robd@reactos.org>
6 * Copyright 2021 Wu Haotian <rigoligo03@gmail.com>
7 * Copyright 2021 Valerij Zaporogeci <vlrzprgts@gmail.com>
8 */
9
10 #include "precomp.h"
11
12 #include <math.h>
13
14 WNDPROC OldGraphCtrlWndProc;
15
16 BOOL
GraphCtrl_Create(PTM_GRAPH_CONTROL inst,HWND hWnd,HWND hParentWnd,PTM_FORMAT fmt)17 GraphCtrl_Create(PTM_GRAPH_CONTROL inst, HWND hWnd, HWND hParentWnd, PTM_FORMAT fmt)
18 {
19 HDC hdc, hdcg;
20 HBITMAP hbmOld;
21 UINT Size;
22 INT p;
23 RECT rc;
24
25 inst->hParentWnd = hParentWnd;
26 inst->hWnd = hWnd;
27
28 Size = GetSystemMetrics(SM_CXSCREEN);
29 inst->BitmapWidth = Size;
30 Size /= PLOT_SHIFT;
31 inst->PointBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size * NUM_PLOTS);
32 if (!inst->PointBuffer)
33 {
34 goto fail;
35 }
36
37 inst->NumberOfPoints = Size;
38 inst->CurrIndex = 0;
39
40 /* Styling */
41 inst->hPenGrid = CreatePen(PS_SOLID, 0, fmt->clrGrid);
42 inst->hPen0 = CreatePen(PS_SOLID, 0, fmt->clrPlot0);
43 inst->hPen1 = CreatePen(PS_SOLID, 0, fmt->clrPlot1);
44 inst->hBrushBack = CreateSolidBrush(fmt->clrBack);
45
46 if (!inst->hPenGrid ||
47 !inst->hPen0 ||
48 !inst->hPen1 ||
49 !inst->hBrushBack)
50 {
51 goto fail;
52 }
53
54 if (fmt->GridCellWidth >= PLOT_SHIFT << 2)
55 inst->GridCellWidth = fmt->GridCellWidth;
56 else
57 inst->GridCellWidth = PLOT_SHIFT << 2;
58 if (fmt->GridCellHeight >= PLOT_SHIFT << 2)
59 inst->GridCellHeight = fmt->GridCellHeight;
60 else
61 inst->GridCellHeight = PLOT_SHIFT << 2;
62
63 inst->DrawSecondaryPlot = fmt->DrawSecondaryPlot;
64
65 GetClientRect(hWnd, &rc);
66 inst->BitmapHeight = rc.bottom;
67 inst->ftPixelsPerPercent = (FLOAT)(inst->BitmapHeight) / 100.00f;
68
69 hdc = GetDC(hParentWnd);
70 hdcg = CreateCompatibleDC(hdc);
71 inst->hdcGraph = hdcg;
72 inst->hbmGraph = CreateCompatibleBitmap(hdc, inst->BitmapWidth, inst->BitmapHeight);
73
74 if (!hdc ||
75 !hdcg ||
76 !inst->hbmGraph)
77 {
78 goto fail;
79 }
80
81 ReleaseDC(hParentWnd, hdc);
82 hbmOld = (HBITMAP)SelectObject(hdcg, inst->hbmGraph);
83 DeleteObject(hbmOld);
84
85 SetBkColor(hdcg, fmt->clrBack);
86 rc.right = inst->BitmapWidth;
87 FillRect(hdcg, &rc, inst->hBrushBack);
88
89 inst->CurrShift = 0;
90 SelectObject(hdcg, inst->hPenGrid);
91 for (p = inst->GridCellHeight - 1;
92 p < inst->BitmapHeight;
93 p += inst->GridCellHeight)
94 {
95 MoveToEx(hdcg, 0, p, NULL);
96 LineTo(hdcg, inst->BitmapWidth, p);
97 }
98 for (p = inst->BitmapWidth - 1;
99 p > 0;
100 p -= inst->GridCellWidth)
101 {
102 MoveToEx(hdcg, p, 0, NULL);
103 LineTo(hdcg, p, inst->BitmapHeight);
104 }
105 SelectObject(hdcg, inst->hPen0);
106
107 return TRUE;
108
109 fail:
110 GraphCtrl_Dispose(inst);
111 return FALSE;
112 }
113
114 void
GraphCtrl_Dispose(PTM_GRAPH_CONTROL inst)115 GraphCtrl_Dispose(PTM_GRAPH_CONTROL inst)
116 {
117 if (inst->PointBuffer)
118 HeapFree(GetProcessHeap(), 0, inst->PointBuffer);
119
120 if (inst->hdcGraph)
121 DeleteDC(inst->hdcGraph);
122
123 if (inst->hPenGrid)
124 DeleteObject(inst->hPenGrid);
125
126 if (inst->hPen0)
127 DeleteObject(inst->hPen0);
128
129 if (inst->hPen1)
130 DeleteObject(inst->hPen1);
131
132 if (inst->hBrushBack)
133 DeleteObject(inst->hBrushBack);
134
135 if (inst->hbmGraph)
136 DeleteObject(inst->hbmGraph);
137 }
138
139 void
GraphCtrl_AddPoint(PTM_GRAPH_CONTROL inst,BYTE val0,BYTE val1)140 GraphCtrl_AddPoint(PTM_GRAPH_CONTROL inst, BYTE val0, BYTE val1)
141 {
142 HDC hdcg;
143 PBYTE t;
144 RECT rcDirt;
145
146 UINT Prev0, Prev1, RetainingWidth;
147 INT PrevY, CurrY, p, v;
148
149 hdcg = inst->hdcGraph;
150 RetainingWidth = inst->BitmapWidth - PLOT_SHIFT;
151 t = inst->PointBuffer;
152 Prev0 = *(t + inst->CurrIndex);
153 Prev1 = *(t + inst->CurrIndex + inst->NumberOfPoints);
154 if (inst->CurrIndex < inst->NumberOfPoints - 1)
155 {
156 inst->CurrIndex++;
157 }
158 else
159 {
160 inst->CurrIndex = 0;
161 }
162 *(t + inst->CurrIndex) = val0;
163 *(t + inst->CurrIndex + inst->NumberOfPoints) = val1;
164
165 /* Drawing points, first shifting the plot left */
166 BitBlt(hdcg, 0, 0, RetainingWidth, inst->BitmapHeight, hdcg, PLOT_SHIFT, 0, SRCCOPY);
167
168 rcDirt.left = RetainingWidth;
169 rcDirt.top = 0;
170 rcDirt.right = inst->BitmapWidth;
171 rcDirt.bottom = inst->BitmapHeight;
172 FillRect(hdcg, &rcDirt, inst->hBrushBack);
173
174 SelectObject(hdcg, inst->hPenGrid);
175 for (p = inst->GridCellHeight - 1;
176 p < inst->BitmapHeight;
177 p += inst->GridCellHeight)
178 {
179 MoveToEx(hdcg, RetainingWidth, p, NULL);
180 LineTo(hdcg, inst->BitmapWidth, p);
181 }
182 v = inst->CurrShift + PLOT_SHIFT;
183 if (v >= inst->GridCellWidth)
184 {
185 v -= inst->GridCellWidth;
186 p = inst->BitmapWidth - v - 1;
187 MoveToEx(hdcg, p, 0, NULL);
188 LineTo(hdcg, p, inst->BitmapHeight);
189 }
190 inst->CurrShift = v;
191
192 if (inst->DrawSecondaryPlot)
193 {
194 SelectObject(inst->hdcGraph, inst->hPen1);
195
196 PrevY = inst->BitmapHeight - Prev1 * inst->ftPixelsPerPercent;
197 MoveToEx(inst->hdcGraph, RetainingWidth - 1, PrevY, NULL);
198 CurrY = inst->BitmapHeight - val1 * inst->ftPixelsPerPercent;
199 LineTo(inst->hdcGraph, inst->BitmapWidth - 1, CurrY);
200 }
201
202 SelectObject(inst->hdcGraph, inst->hPen0);
203 PrevY = inst->BitmapHeight - Prev0 * inst->ftPixelsPerPercent;
204 MoveToEx(inst->hdcGraph, RetainingWidth - 1, PrevY, NULL);
205 CurrY = inst->BitmapHeight - val0 * inst->ftPixelsPerPercent;
206 LineTo(inst->hdcGraph, inst->BitmapWidth - 1, CurrY);
207 }
208
209 inline void
GraphCtrl_RedrawBitmap(PTM_GRAPH_CONTROL inst,INT h)210 GraphCtrl_RedrawBitmap(PTM_GRAPH_CONTROL inst, INT h)
211 {
212 HDC hdcg;
213 PBYTE t;
214 RECT rc;
215 INT i, j, y, x, p;
216 FLOAT coef;
217
218 hdcg = inst->hdcGraph;
219 rc.left = 0; rc.top = 0;
220 rc.right = inst->BitmapWidth; rc.bottom = h;
221 FillRect(hdcg, &rc, inst->hBrushBack);
222
223 SelectObject(hdcg, inst->hPenGrid);
224
225 for (p = inst->GridCellHeight - 1;
226 p < inst->BitmapHeight;
227 p += inst->GridCellHeight)
228 {
229 MoveToEx(hdcg, 0, p, NULL);
230 LineTo(hdcg, inst->BitmapWidth, p);
231 }
232
233 for (p = inst->BitmapWidth - inst->CurrShift - 1;
234 p > 0;
235 p -= inst->GridCellWidth)
236 {
237 MoveToEx(hdcg, p, 0, NULL);
238 LineTo(hdcg, p, inst->BitmapHeight);
239 }
240
241 coef = inst->ftPixelsPerPercent;
242
243 if (inst->DrawSecondaryPlot)
244 {
245 SelectObject(hdcg, inst->hPen1);
246 t = inst->PointBuffer + inst->NumberOfPoints;
247 x = inst->BitmapWidth - 1;
248 j = inst->CurrIndex;
249 y = h - *(t + j) * coef;
250 MoveToEx(hdcg, x, y, NULL);
251 for (i = 0; i < inst->NumberOfPoints; i++)
252 {
253 j = (j ? j : inst->NumberOfPoints) - 1;
254 y = h - *(t + j) * coef;
255 x -= PLOT_SHIFT;
256 LineTo(hdcg, x, y);
257 }
258 }
259
260 SelectObject(hdcg, inst->hPen0);
261 t = inst->PointBuffer;
262 x = inst->BitmapWidth - 1;
263 j = inst->CurrIndex;
264 y = h - *(t + j) * coef;
265 MoveToEx(hdcg, x, y, NULL);
266
267 for (i = 0; i < inst->NumberOfPoints; i++)
268 {
269 j = (j ? j : inst->NumberOfPoints) - 1;
270 y = h - *(t + j) * coef;
271 x -= PLOT_SHIFT;
272 LineTo(hdcg, x, y);
273 }
274 }
275
276 inline void
GraphCtrl_RedrawOnHeightChange(PTM_GRAPH_CONTROL inst,INT nh)277 GraphCtrl_RedrawOnHeightChange(PTM_GRAPH_CONTROL inst, INT nh)
278 {
279 HDC hdc;
280 HBITMAP hbmOld;
281
282 inst->BitmapHeight = nh;
283 inst->ftPixelsPerPercent = (FLOAT)nh / 100.00f;
284
285 hdc = GetDC(inst->hParentWnd);
286 hbmOld = inst->hbmGraph;
287 inst->hbmGraph = CreateCompatibleBitmap(hdc, inst->BitmapWidth, nh);
288 SelectObject(inst->hdcGraph, inst->hbmGraph);
289 DeleteObject(hbmOld);
290 ReleaseDC(inst->hParentWnd, hdc);
291
292 GraphCtrl_RedrawBitmap(inst, nh);
293 }
294
295 extern TM_GRAPH_CONTROL PerformancePageCpuUsageHistoryGraph;
296 extern TM_GRAPH_CONTROL PerformancePageMemUsageHistoryGraph;
297 extern HWND hPerformancePageCpuUsageHistoryGraph;
298 extern HWND hPerformancePageMemUsageHistoryGraph;
299
300 INT_PTR CALLBACK
GraphCtrl_WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)301 GraphCtrl_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
302 {
303 PTM_GRAPH_CONTROL graph;
304
305 switch (message)
306 {
307 case WM_ERASEBKGND:
308 return TRUE;
309 /*
310 * Filter out mouse & keyboard messages
311 */
312 // case WM_APPCOMMAND:
313 case WM_CAPTURECHANGED:
314 case WM_LBUTTONDBLCLK:
315 case WM_LBUTTONDOWN:
316 case WM_LBUTTONUP:
317 case WM_MBUTTONDBLCLK:
318 case WM_MBUTTONDOWN:
319 case WM_MBUTTONUP:
320 case WM_MOUSEACTIVATE:
321 case WM_MOUSEHOVER:
322 case WM_MOUSELEAVE:
323 case WM_MOUSEMOVE:
324 // case WM_MOUSEWHEEL:
325 case WM_NCHITTEST:
326 case WM_NCLBUTTONDBLCLK:
327 case WM_NCLBUTTONDOWN:
328 case WM_NCLBUTTONUP:
329 case WM_NCMBUTTONDBLCLK:
330 case WM_NCMBUTTONDOWN:
331 case WM_NCMBUTTONUP:
332 // case WM_NCMOUSEHOVER:
333 // case WM_NCMOUSELEAVE:
334 case WM_NCMOUSEMOVE:
335 case WM_NCRBUTTONDBLCLK:
336 case WM_NCRBUTTONDOWN:
337 case WM_NCRBUTTONUP:
338 // case WM_NCXBUTTONDBLCLK:
339 // case WM_NCXBUTTONDOWN:
340 // case WM_NCXBUTTONUP:
341 case WM_RBUTTONDBLCLK:
342 case WM_RBUTTONDOWN:
343 case WM_RBUTTONUP:
344 // case WM_XBUTTONDBLCLK:
345 // case WM_XBUTTONDOWN:
346 // case WM_XBUTTONUP:
347 case WM_ACTIVATE:
348 case WM_CHAR:
349 case WM_DEADCHAR:
350 case WM_GETHOTKEY:
351 case WM_HOTKEY:
352 case WM_KEYDOWN:
353 case WM_KEYUP:
354 case WM_KILLFOCUS:
355 case WM_SETFOCUS:
356 case WM_SETHOTKEY:
357 case WM_SYSCHAR:
358 case WM_SYSDEADCHAR:
359 case WM_SYSKEYDOWN:
360 case WM_SYSKEYUP:
361 return 0;
362
363 case WM_NCCALCSIZE:
364 return 0;
365
366 case WM_SIZE:
367 {
368 if (hWnd == hPerformancePageCpuUsageHistoryGraph)
369 graph = &PerformancePageCpuUsageHistoryGraph;
370 else if (hWnd == hPerformancePageMemUsageHistoryGraph)
371 graph = &PerformancePageMemUsageHistoryGraph;
372 else
373 return 0;
374
375 if (HIWORD(lParam) != graph->BitmapHeight)
376 {
377 GraphCtrl_RedrawOnHeightChange(graph, HIWORD(lParam));
378 }
379 InvalidateRect(hWnd, NULL, FALSE);
380
381 return 0;
382 }
383
384 case WM_PAINT:
385 {
386 RECT rcClient;
387 HDC hdc;
388 PAINTSTRUCT ps;
389
390 if (hWnd == hPerformancePageCpuUsageHistoryGraph)
391 graph = &PerformancePageCpuUsageHistoryGraph;
392 else if (hWnd == hPerformancePageMemUsageHistoryGraph)
393 graph = &PerformancePageMemUsageHistoryGraph;
394 else
395 return 0;
396
397 hdc = BeginPaint(hWnd, &ps);
398 GetClientRect(hWnd, &rcClient);
399 BitBlt(hdc, 0, 0,
400 rcClient.right,
401 rcClient.bottom,
402 graph->hdcGraph,
403 graph->BitmapWidth - rcClient.right,
404 0,
405 SRCCOPY);
406 EndPaint(hWnd, &ps);
407 return 0;
408 }
409 }
410
411 /*
412 * We pass on all non-handled messages
413 */
414 return CallWindowProcW(OldGraphCtrlWndProc, hWnd, message, wParam, lParam);
415 }
416