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