winetest: Make sure we can test .NET dlls on Windows.
[wine] / programs / taskmgr / graph.c
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     
24 #define WIN32_LEAN_AND_MEAN    /* Exclude rarely-used stuff from Windows headers */
25 #include <windows.h>
26 #include <commctrl.h>
27 #include <stdlib.h>
28 #include <memory.h>
29 #include <stdio.h>
30 #include <winnt.h>
31     
32 #include "wine/unicode.h"
33 #include "taskmgr.h"
34 #include "perfdata.h"
35
36 #define BRIGHT_GREEN    RGB(0, 255, 0)
37 #define DARK_GREEN      RGB(0, 130, 0)
38 #define RED             RGB(255, 0, 0)
39
40
41 WNDPROC             OldGraphWndProc;
42
43 static void Graph_DrawCpuUsageGraph(HDC hDC, HWND hWnd)
44 {
45     RECT            rcClient;
46     RECT            rcBarLeft;
47     RECT            rcBarRight;
48     WCHAR            Text[256];
49     ULONG            CpuUsage;
50     ULONG            CpuKernelUsage;
51     int                nBars;
52     int                nBarsUsed; 
53 /* Bottom bars that are "used", i.e. are bright green, representing used cpu time */
54     int                nBarsUsedKernel; 
55 /* Bottom bars that are "used", i.e. are bright green, representing used cpu kernel time */
56     int                nBarsFree; 
57 /* Top bars that are "unused", i.e. are dark green, representing free cpu time */
58     int                i;
59
60     static const WCHAR    wszFormatI[] = {'%','d','%','%',0};
61     static const WCHAR    wszFormatII[] = {' ',' ','%','d','%','%',0};
62     static const WCHAR    wszFormatIII[] = {' ','%','d','%','%',0};
63     
64     /*
65      * Get the client area rectangle
66      */
67     GetClientRect(hWnd, &rcClient);
68     
69     /*
70      * Fill it with blackness
71      */
72     FillSolidRect(hDC, &rcClient, RGB(0, 0, 0));
73     
74     /*
75      * Get the CPU usage
76      */
77     CpuUsage = PerfDataGetProcessorUsage();
78     CpuKernelUsage = PerfDataGetProcessorSystemUsage();
79
80     /*
81      * Check and see how many digits it will take
82      * so we get the indentation right every time.
83      */
84     if (CpuUsage == 100)
85     {
86         sprintfW(Text, wszFormatI, (int)CpuUsage);
87     }
88     else if (CpuUsage < 10)
89     {
90         sprintfW(Text, wszFormatII, (int)CpuUsage);
91     }
92     else
93     {
94         sprintfW(Text, wszFormatIII, (int)CpuUsage);
95     }
96     
97     /*
98      * Draw the font text onto the graph
99      * The bottom 20 pixels are reserved for the text
100      */
101     Font_DrawText(hDC, Text, ((rcClient.right - rcClient.left) - 32) / 2, rcClient.bottom - 11 - 5);
102
103     /*
104      * Now we have to draw the graph
105      * So first find out how many bars we can fit
106      */
107     nBars = ((rcClient.bottom - rcClient.top) - 25) / 3;
108     nBarsUsed = (nBars * CpuUsage) / 100;
109     if ((CpuUsage) && (nBarsUsed == 0))
110     {
111         nBarsUsed = 1;
112     }
113     nBarsFree = nBars - nBarsUsed;
114     if (TaskManagerSettings.ShowKernelTimes)
115     {
116         nBarsUsedKernel = ((nBars * 2) * CpuKernelUsage) / 100;
117         nBarsUsed -= (nBarsUsedKernel / 2);
118     }
119     else
120     {
121         nBarsUsedKernel = 0;
122     }
123
124     /*
125      * Now draw the bar graph
126      */
127     rcBarLeft.left =  ((rcClient.right - rcClient.left) - 33) / 2;
128     rcBarLeft.right =  rcBarLeft.left + 16;
129     rcBarRight.left = rcBarLeft.left + 17;
130     rcBarRight.right = rcBarLeft.right + 17;
131     rcBarLeft.top = rcBarRight.top = 5;
132     rcBarLeft.bottom = rcBarRight.bottom = 7;
133
134     if (nBarsUsed < 0)     nBarsUsed = 0;
135     if (nBarsUsed > nBars) nBarsUsed = nBars;
136
137     if (nBarsFree < 0)     nBarsFree = 0;
138     if (nBarsFree > nBars) nBarsFree = nBars;
139
140     if (nBarsUsedKernel < 0)     nBarsUsedKernel = 0;
141     if (nBarsUsedKernel > nBars) nBarsUsedKernel = nBars;
142
143     /*
144      * Draw the "free" bars
145      */
146     for (i=0; i<nBarsFree; i++)
147     {
148         FillSolidRect(hDC, &rcBarLeft, DARK_GREEN);
149         FillSolidRect(hDC, &rcBarRight, DARK_GREEN);
150         
151         rcBarLeft.top += 3;
152         rcBarLeft.bottom += 3;
153         
154         rcBarRight.top += 3;
155         rcBarRight.bottom += 3;
156     }
157     
158     /*
159      * Draw the "used" bars
160      */
161     for (i=0; i<nBarsUsed; i++)
162     {
163         if (nBarsUsed > 5000) nBarsUsed = 5000;
164
165         FillSolidRect(hDC, &rcBarLeft, BRIGHT_GREEN);
166         FillSolidRect(hDC, &rcBarRight, BRIGHT_GREEN);
167         
168         rcBarLeft.top += 3;
169         rcBarLeft.bottom += 3;
170         
171         rcBarRight.top += 3;
172         rcBarRight.bottom += 3;
173     }
174     
175     /*
176      * Draw the "used" kernel bars
177      */
178     rcBarLeft.bottom--;
179     rcBarRight.bottom--;
180     if (nBarsUsedKernel && nBarsUsedKernel % 2)
181     {
182         rcBarLeft.top -= 2;
183         rcBarLeft.bottom -= 2;
184         
185         rcBarRight.top -= 2;
186         rcBarRight.bottom -= 2;
187
188         FillSolidRect(hDC, &rcBarLeft, RED);
189         FillSolidRect(hDC, &rcBarRight, RED);
190         
191         rcBarLeft.top += 2;
192         rcBarLeft.bottom += 2;
193         
194         rcBarRight.top += 2;
195         rcBarRight.bottom += 2;
196
197         nBarsUsedKernel--;
198     }
199     for (i=0; i<nBarsUsedKernel; i++)
200     {
201         if (nBarsUsedKernel > 5000) nBarsUsedKernel = 5000;
202
203         FillSolidRect(hDC, &rcBarLeft, RED);
204         FillSolidRect(hDC, &rcBarRight, RED);
205         
206         rcBarLeft.top++;
207         rcBarLeft.bottom++;
208         
209         rcBarRight.top++;
210         rcBarRight.bottom++;
211
212         if (i % 2)
213         {
214             rcBarLeft.top++;
215             rcBarLeft.bottom++;
216             
217             rcBarRight.top++;
218             rcBarRight.bottom++;
219         }
220     }
221 }
222
223 static void Graph_DrawMemUsageGraph(HDC hDC, HWND hWnd)
224 {
225     RECT            rcClient;
226     RECT            rcBarLeft;
227     RECT            rcBarRight;
228     WCHAR            Text[256];
229     ULONGLONG        CommitChargeTotal;
230     ULONGLONG        CommitChargeLimit;
231     int                nBars;
232     int                nBarsUsed = 0; 
233 /* Bottom bars that are "used", i.e. are bright green, representing used memory */
234     int                nBarsFree; 
235 /* Top bars that are "unused", i.e. are dark green, representing free memory */
236     int                i;
237
238     static const WCHAR    wszFormat[] = {'%','d','K',0};
239     
240     /*
241      * Get the client area rectangle
242      */
243     GetClientRect(hWnd, &rcClient);
244     
245     /*
246      * Fill it with blackness
247      */
248     FillSolidRect(hDC, &rcClient, RGB(0, 0, 0));
249     
250     /*
251      * Get the memory usage
252      */
253     CommitChargeTotal = (ULONGLONG)PerfDataGetCommitChargeTotalK();
254     CommitChargeLimit = (ULONGLONG)PerfDataGetCommitChargeLimitK();
255
256     sprintfW(Text, wszFormat, (int)CommitChargeTotal);
257     
258     /*
259      * Draw the font text onto the graph
260      * The bottom 20 pixels are reserved for the text
261      */
262     Font_DrawText(hDC, Text, ((rcClient.right - rcClient.left) - (strlenW(Text) * 8)) / 2, rcClient.bottom - 11 - 5);
263
264     /*
265      * Now we have to draw the graph
266      * So first find out how many bars we can fit
267      */
268     nBars = ((rcClient.bottom - rcClient.top) - 25) / 3;
269         if (CommitChargeLimit)
270     nBarsUsed = (nBars * (int)((CommitChargeTotal * 100) / CommitChargeLimit)) / 100;
271     nBarsFree = nBars - nBarsUsed;
272
273     if (nBarsUsed < 0)     nBarsUsed = 0;
274     if (nBarsUsed > nBars) nBarsUsed = nBars;
275
276     if (nBarsFree < 0)     nBarsFree = 0;
277     if (nBarsFree > nBars) nBarsFree = nBars;
278
279     /*
280      * Now draw the bar graph
281      */
282     rcBarLeft.left =  ((rcClient.right - rcClient.left) - 33) / 2;
283     rcBarLeft.right =  rcBarLeft.left + 16;
284     rcBarRight.left = rcBarLeft.left + 17;
285     rcBarRight.right = rcBarLeft.right + 17;
286     rcBarLeft.top = rcBarRight.top = 5;
287     rcBarLeft.bottom = rcBarRight.bottom = 7;
288     
289     /*
290      * Draw the "free" bars
291      */
292     for (i=0; i<nBarsFree; i++)
293     {
294         FillSolidRect(hDC, &rcBarLeft, DARK_GREEN);
295         FillSolidRect(hDC, &rcBarRight, DARK_GREEN);
296         
297         rcBarLeft.top += 3;
298         rcBarLeft.bottom += 3;
299         
300         rcBarRight.top += 3;
301         rcBarRight.bottom += 3;
302     }
303     
304     /*
305      * Draw the "used" bars
306      */
307     for (i=0; i<nBarsUsed; i++)
308     {
309         FillSolidRect(hDC, &rcBarLeft, BRIGHT_GREEN);
310         FillSolidRect(hDC, &rcBarRight, BRIGHT_GREEN);
311         
312         rcBarLeft.top += 3;
313         rcBarLeft.bottom += 3;
314         
315         rcBarRight.top += 3;
316         rcBarRight.bottom += 3;
317     }
318 }
319
320 static void Graph_DrawMemUsageHistoryGraph(HDC hDC, HWND hWnd)
321 {
322     RECT            rcClient;
323     ULONGLONG        CommitChargeLimit;
324     int                i;
325     static int        offset = 0;
326     
327     if (offset++ >= 10)
328         offset = 0;
329     
330     /*
331      * Get the client area rectangle
332      */
333     GetClientRect(hWnd, &rcClient);
334     
335     /*
336      * Fill it with blackness
337      */
338     FillSolidRect(hDC, &rcClient, RGB(0, 0, 0));
339
340     /*
341      * Get the memory usage
342      */
343     CommitChargeLimit = (ULONGLONG)PerfDataGetCommitChargeLimitK();
344
345     /*
346      * Draw the graph background
347      *
348      * Draw the horizontal bars
349      */
350     for (i=0; i<rcClient.bottom; i++)
351     {
352         if ((i % 11) == 0)
353         {
354             /* FillSolidRect2(hDC, 0, i, rcClient.right, 1, DARK_GREEN);  */
355         }
356     }
357     /*
358      * Draw the vertical bars
359      */
360     for (i=11; i<rcClient.right + offset; i++)
361     {
362         if ((i % 11) == 0)
363         {
364             /* FillSolidRect2(hDC, i - offset, 0, 1, rcClient.bottom, DARK_GREEN);  */
365         }
366     }
367
368     /*
369      * Draw the memory usage
370      */
371     for (i=rcClient.right; i>=0; i--)
372     {
373     }
374 }
375
376 INT_PTR CALLBACK
377 Graph_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
378 {
379     HDC                hdc;
380     PAINTSTRUCT        ps;
381     LONG            WindowId;
382     
383     switch (message)
384     {
385     case WM_ERASEBKGND:
386         return TRUE;
387
388     /*
389      * Filter out mouse  & keyboard messages
390      */
391     /* case WM_APPCOMMAND: */
392     case WM_CAPTURECHANGED:
393     case WM_LBUTTONDBLCLK:
394     case WM_LBUTTONDOWN:
395     case WM_LBUTTONUP:
396     case WM_MBUTTONDBLCLK:
397     case WM_MBUTTONDOWN:
398     case WM_MBUTTONUP:
399     case WM_MOUSEACTIVATE:
400     case WM_MOUSEHOVER:
401     case WM_MOUSELEAVE:
402     case WM_MOUSEMOVE:
403     /* case WM_MOUSEWHEEL: */
404     case WM_NCHITTEST:
405     case WM_NCLBUTTONDBLCLK:
406     case WM_NCLBUTTONDOWN:
407     case WM_NCLBUTTONUP:
408     case WM_NCMBUTTONDBLCLK:
409     case WM_NCMBUTTONDOWN:
410     case WM_NCMBUTTONUP:
411     /* case WM_NCMOUSEHOVER: */
412     /* case WM_NCMOUSELEAVE: */
413     case WM_NCMOUSEMOVE:
414     case WM_NCRBUTTONDBLCLK:
415     case WM_NCRBUTTONDOWN:
416     case WM_NCRBUTTONUP:
417     /* case WM_NCXBUTTONDBLCLK: */
418     /* case WM_NCXBUTTONDOWN: */
419     /* case WM_NCXBUTTONUP: */
420     case WM_RBUTTONDBLCLK:
421     case WM_RBUTTONDOWN:
422     case WM_RBUTTONUP:
423     /* case WM_XBUTTONDBLCLK: */
424     /* case WM_XBUTTONDOWN: */
425     /* case WM_XBUTTONUP: */
426     case WM_ACTIVATE:
427     case WM_CHAR:
428     case WM_DEADCHAR:
429     case WM_GETHOTKEY:
430     case WM_HOTKEY:
431     case WM_KEYDOWN:
432     case WM_KEYUP:
433     case WM_KILLFOCUS:
434     case WM_SETFOCUS:
435     case WM_SETHOTKEY:
436     case WM_SYSCHAR:
437     case WM_SYSDEADCHAR:
438     case WM_SYSKEYDOWN:
439     case WM_SYSKEYUP:
440             
441     case WM_NCCALCSIZE:
442         return 0;
443
444     case WM_PAINT:
445         
446         hdc = BeginPaint(hWnd, &ps);
447
448         WindowId = GetWindowLongPtr(hWnd, GWLP_ID);
449
450         switch (WindowId)
451         {
452         case IDC_CPU_USAGE_GRAPH:
453             Graph_DrawCpuUsageGraph(hdc, hWnd);
454             break;
455         case IDC_MEM_USAGE_GRAPH:
456             Graph_DrawMemUsageGraph(hdc, hWnd);
457             break;
458         case IDC_MEM_USAGE_HISTORY_GRAPH:
459             Graph_DrawMemUsageHistoryGraph(hdc, hWnd);
460             break;
461         }
462         
463         EndPaint(hWnd, &ps);
464         
465         return 0;
466         
467     }
468     
469     /*
470      * We pass on all non-handled messages
471      */
472     return CallWindowProc((WNDPROC)OldGraphWndProc, hWnd, message, wParam, lParam);
473 }