cmd: Prevent external env vars causing tests to fail.
[wine] / programs / taskmgr / graphctl.c
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
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <math.h>
26
27 #include <windows.h>
28 #include <commctrl.h>
29 #include "graphctl.h"
30 #include "taskmgr.h"
31
32 WNDPROC OldGraphCtrlWndProc;
33
34 static void GraphCtrl_Init(TGraphCtrl* this)
35 {
36     int i;
37
38     this->m_hWnd = 0;
39     this->m_hParentWnd = 0;
40     this->m_dcGrid = 0;
41     this->m_dcPlot = 0; 
42     this->m_bitmapOldGrid = 0;
43     this->m_bitmapOldPlot = 0;
44     this->m_bitmapGrid = 0;
45     this->m_bitmapPlot = 0;
46     this->m_brushBack = 0;
47     
48     this->m_penPlot[0] = 0;
49     this->m_penPlot[1] = 0;
50     this->m_penPlot[2] = 0;
51     this->m_penPlot[3] = 0;
52     
53     /* since plotting is based on a LineTo for each new point
54      * we need a starting point (i.e. a "previous" point)
55      * use 0.0 as the default first point.
56      * these are public member variables, and can be changed outside
57      * (after construction).  Therefore m_dPreviousPosition could be set to
58      * a more appropriate value prior to the first call to SetPosition.
59      */
60     this->m_dPreviousPosition[0] = 0.0;
61     this->m_dPreviousPosition[1] = 0.0;
62     this->m_dPreviousPosition[2] = 0.0;
63     this->m_dPreviousPosition[3] = 0.0;
64
65     /*  public variable for the number of decimal places on the y axis */
66     this->m_nYDecimals = 3;
67
68     /*  set some initial values for the scaling until "SetRange" is called.
69      *  these are protected variables and must be set with SetRange
70      *  in order to ensure that m_dRange is updated accordingly
71      */
72     /*   m_dLowerLimit = -10.0; */
73     /*   m_dUpperLimit =  10.0; */
74     this->m_dLowerLimit = 0.0;
75     this->m_dUpperLimit = 100.0;
76     this->m_dRange      =  this->m_dUpperLimit - this->m_dLowerLimit;   /*  protected member variable */
77
78     /*  m_nShiftPixels determines how much the plot shifts (in terms of pixels)  */
79     /*  with the addition of a new data point */
80     this->m_nShiftPixels     = 4;
81     this->m_nHalfShiftPixels = this->m_nShiftPixels/2;                     /*  protected */
82     this->m_nPlotShiftPixels = this->m_nShiftPixels + this->m_nHalfShiftPixels;  /*  protected */
83
84     /*  background, grid and data colors */
85     /*  these are public variables and can be set directly */
86     this->m_crBackColor = RGB(  0,   0,   0);  /*  see also SetBackgroundColor */
87     this->m_crGridColor = RGB(  0, 255, 255);  /*  see also SetGridColor */
88     this->m_crPlotColor[0] = RGB(255, 255, 255);  /*  see also SetPlotColor */
89     this->m_crPlotColor[1] = RGB(100, 255, 255);  /*  see also SetPlotColor */
90     this->m_crPlotColor[2] = RGB(255, 100, 255);  /*  see also SetPlotColor */
91     this->m_crPlotColor[3] = RGB(255, 255, 100);  /*  see also SetPlotColor */
92
93     /*  protected variables */
94     for (i = 0; i < MAX_PLOTS; i++) 
95     {
96         this->m_penPlot[i] = CreatePen(PS_SOLID, 0, this->m_crPlotColor[i]);
97     }
98     this->m_brushBack = CreateSolidBrush(this->m_crBackColor);
99
100     /*  public member variables, can be set directly  */
101     strcpy(this->m_strXUnitsString, "Samples");  /*  can also be set with SetXUnits */
102     strcpy(this->m_strYUnitsString, "Y units");  /*  can also be set with SetYUnits */
103
104     /*  protected bitmaps to restore the memory DC's */
105     this->m_bitmapOldGrid = NULL;
106     this->m_bitmapOldPlot = NULL;
107 }
108
109 #if 0
110 TGraphCtrl::~TGraphCtrl(void)
111 {
112     /*  just to be picky restore the bitmaps for the two memory dc's */
113     /*  (these dc's are being destroyed so there shouldn't be any leaks) */
114     if (m_bitmapOldGrid != NULL) SelectObject(m_dcGrid, m_bitmapOldGrid);  
115     if (m_bitmapOldPlot != NULL) SelectObject(m_dcPlot, m_bitmapOldPlot);  
116     if (m_bitmapGrid    != NULL) DeleteObject(m_bitmapGrid);
117     if (m_bitmapPlot    != NULL) DeleteObject(m_bitmapPlot);
118     if (m_dcGrid        != NULL) DeleteDC(m_dcGrid);
119     if (m_dcPlot        != NULL) DeleteDC(m_dcPlot);
120     if (m_brushBack     != NULL) DeleteObject(m_brushBack);
121 }
122 #endif
123
124 static void GraphCtrl_Resize(TGraphCtrl* this)
125 {
126     /*  NOTE: Resize automatically gets called during the setup of the control */
127     GetClientRect(this->m_hWnd, &this->m_rectClient);
128
129     /*  set some member variables to avoid multiple function calls */
130     this->m_nClientHeight = this->m_rectClient.bottom - this->m_rectClient.top;/* m_rectClient.Height(); */
131     this->m_nClientWidth  = this->m_rectClient.right - this->m_rectClient.left;/* m_rectClient.Width(); */
132
133     /*  the "left" coordinate and "width" will be modified in  */
134     /*  InvalidateCtrl to be based on the width of the y axis scaling */
135 #if 0
136     this->m_rectPlot.left   = 20;
137     this->m_rectPlot.top    = 10;
138     this->m_rectPlot.right  = this->m_rectClient.right-10;
139     this->m_rectPlot.bottom = this->m_rectClient.bottom-25;
140 #else
141     this->m_rectPlot.left   = 0;
142     this->m_rectPlot.top    = -1;
143     this->m_rectPlot.right  = this->m_rectClient.right-0;
144     this->m_rectPlot.bottom = this->m_rectClient.bottom-0;
145 #endif
146
147     /*  set some member variables to avoid multiple function calls */
148     this->m_nPlotHeight = this->m_rectPlot.bottom - this->m_rectPlot.top;/* m_rectPlot.Height(); */
149     this->m_nPlotWidth  = this->m_rectPlot.right - this->m_rectPlot.left;/* m_rectPlot.Width(); */
150
151     /*  set the scaling factor for now, this can be adjusted  */
152     /*  in the SetRange functions */
153     this->m_dVerticalFactor = (double)this->m_nPlotHeight / this->m_dRange;
154 }
155
156 BOOL GraphCtrl_Create(TGraphCtrl* this, HWND hWnd, HWND hParentWnd, UINT nID)
157 {
158     GraphCtrl_Init(this);
159     this->m_hParentWnd = hParentWnd;
160     this->m_hWnd = hWnd;
161     GraphCtrl_Resize(this);
162     return 0;
163 }
164
165 static void GraphCtrl_InvalidateCtrl(TGraphCtrl* this)
166 {
167     /*  There is a lot of drawing going on here - particularly in terms of  */
168     /*  drawing the grid.  Don't panic, this is all being drawn (only once) */
169     /*  to a bitmap.  The result is then BitBlt'd to the control whenever needed. */
170     int i, j;
171     int nCharacters;
172     int nTopGridPix, nMidGridPix, nBottomGridPix;
173
174     HPEN oldPen;
175     HPEN solidPen = CreatePen(PS_SOLID, 0, this->m_crGridColor);
176     /* HFONT axisFont, yUnitFont, oldFont; */
177     /* char strTemp[50]; */
178
179     /*  in case we haven't established the memory dc's */
180     /* CClientDC dc(this); */
181     HDC dc = GetDC(this->m_hParentWnd);
182
183     /*  if we don't have one yet, set up a memory dc for the grid */
184     if (this->m_dcGrid == NULL)
185     {
186         this->m_dcGrid = CreateCompatibleDC(dc);
187         this->m_bitmapGrid = CreateCompatibleBitmap(dc, this->m_nClientWidth, this->m_nClientHeight);
188         this->m_bitmapOldGrid = SelectObject(this->m_dcGrid, this->m_bitmapGrid);
189     }
190   
191     SetBkColor(this->m_dcGrid, this->m_crBackColor);
192
193     /*  fill the grid background */
194     FillRect(this->m_dcGrid, &this->m_rectClient, this->m_brushBack);
195
196     /*  draw the plot rectangle: */
197     /*  determine how wide the y axis scaling values are */
198     nCharacters = abs((int)log10(fabs(this->m_dUpperLimit)));
199     nCharacters = max(nCharacters, abs((int)log10(fabs(this->m_dLowerLimit))));
200
201     /*  add the units digit, decimal point and a minus sign, and an extra space */
202     /*  as well as the number of decimal places to display */
203     nCharacters = nCharacters + 4 + this->m_nYDecimals;  
204
205     /*  adjust the plot rectangle dimensions */
206     /*  assume 6 pixels per character (this may need to be adjusted) */
207     /*   m_rectPlot.left = m_rectClient.left + 6*(nCharacters); */
208     this->m_rectPlot.left = this->m_rectClient.left;
209     this->m_nPlotWidth    = this->m_rectPlot.right - this->m_rectPlot.left;/* m_rectPlot.Width(); */
210
211     /*  draw the plot rectangle */
212     oldPen = SelectObject(this->m_dcGrid, solidPen);
213     MoveToEx(this->m_dcGrid, this->m_rectPlot.left, this->m_rectPlot.top, NULL);
214     LineTo(this->m_dcGrid, this->m_rectPlot.right+1, this->m_rectPlot.top);
215     LineTo(this->m_dcGrid, this->m_rectPlot.right+1, this->m_rectPlot.bottom+1);
216     LineTo(this->m_dcGrid, this->m_rectPlot.left, this->m_rectPlot.bottom+1);
217     /*   LineTo(m_dcGrid, m_rectPlot.left, m_rectPlot.top); */
218     SelectObject(this->m_dcGrid, oldPen); 
219     DeleteObject(solidPen);
220
221     /*  draw the dotted lines, 
222      *  use SetPixel instead of a dotted pen - this allows for a 
223      *  finer dotted line and a more "technical" look
224      */
225     nMidGridPix    = (this->m_rectPlot.top + this->m_rectPlot.bottom)/2;
226     nTopGridPix    = nMidGridPix - this->m_nPlotHeight/4;
227     nBottomGridPix = nMidGridPix + this->m_nPlotHeight/4;
228
229     for (i=this->m_rectPlot.left; i<this->m_rectPlot.right; i+=2) 
230     {
231         SetPixel(this->m_dcGrid, i, nTopGridPix,    this->m_crGridColor);
232         SetPixel(this->m_dcGrid, i, nMidGridPix,    this->m_crGridColor);
233         SetPixel(this->m_dcGrid, i, nBottomGridPix, this->m_crGridColor);
234     }
235
236     for (i=this->m_rectPlot.left; i<this->m_rectPlot.right; i+=10)
237     {
238         for (j=this->m_rectPlot.top; j<this->m_rectPlot.bottom; j+=2)
239         {
240             SetPixel(this->m_dcGrid, i, j, this->m_crGridColor);
241             /*       SetPixel(m_dcGrid, i, j, m_crGridColor); */
242             /*       SetPixel(m_dcGrid, i, j, m_crGridColor); */
243         }
244     }
245
246 #if 0
247     /*  create some fonts (horizontal and vertical) */
248     /*  use a height of 14 pixels and 300 weight  */
249     /*  (these may need to be adjusted depending on the display) */
250     axisFont = CreateFont (14, 0, 0, 0, 300,
251                            FALSE, FALSE, 0, ANSI_CHARSET,
252                            OUT_DEFAULT_PRECIS, 
253                            CLIP_DEFAULT_PRECIS,
254                            DEFAULT_QUALITY, 
255                            DEFAULT_PITCH|FF_SWISS, "Arial");
256     yUnitFont = CreateFont (14, 0, 900, 0, 300,
257                             FALSE, FALSE, 0, ANSI_CHARSET,
258                             OUT_DEFAULT_PRECIS, 
259                             CLIP_DEFAULT_PRECIS,
260                             DEFAULT_QUALITY, 
261                             DEFAULT_PITCH|FF_SWISS, "Arial");
262   
263     /*  grab the horizontal font */
264     oldFont = SelectObject(m_dcGrid, axisFont);
265   
266     /*  y max */
267     SetTextColor(m_dcGrid, m_crGridColor);
268     SetTextAlign(m_dcGrid, TA_RIGHT|TA_TOP);
269     sprintf(strTemp, "%.*lf", m_nYDecimals, m_dUpperLimit);
270     TextOut(m_dcGrid, m_rectPlot.left-4, m_rectPlot.top, strTemp, _tcslen(strTemp));
271
272     /*  y min */
273     SetTextAlign(m_dcGrid, TA_RIGHT|TA_BASELINE);
274     sprintf(strTemp, "%.*lf", m_nYDecimals, m_dLowerLimit);
275     TextOut(m_dcGrid, m_rectPlot.left-4, m_rectPlot.bottom, strTemp, _tcslen(strTemp));
276
277     /*  x min */
278     SetTextAlign(m_dcGrid, TA_LEFT|TA_TOP);
279     TextOut(m_dcGrid, m_rectPlot.left, m_rectPlot.bottom+4, "0", 1);
280
281     /*  x max */
282     SetTextAlign(m_dcGrid, TA_RIGHT|TA_TOP);
283     sprintf(strTemp, "%d", m_nPlotWidth/m_nShiftPixels); 
284     TextOut(m_dcGrid, m_rectPlot.right, m_rectPlot.bottom+4, strTemp, _tcslen(strTemp));
285
286     /*  x units */
287     SetTextAlign(m_dcGrid, TA_CENTER|TA_TOP);
288     TextOut(m_dcGrid, (m_rectPlot.left+m_rectPlot.right)/2, 
289             m_rectPlot.bottom+4, m_strXUnitsString, _tcslen(m_strXUnitsString));
290
291     /*  restore the font */
292     SelectObject(m_dcGrid, oldFont);
293
294     /*  y units */
295     oldFont = SelectObject(m_dcGrid, yUnitFont);
296     SetTextAlign(m_dcGrid, TA_CENTER|TA_BASELINE);
297     TextOut(m_dcGrid, (m_rectClient.left+m_rectPlot.left)/2, 
298             (m_rectPlot.bottom+m_rectPlot.top)/2, m_strYUnitsString, _tcslen(m_strYUnitsString));
299     SelectObject(m_dcGrid, oldFont);
300 #endif
301     /*  at this point we are done filling the grid bitmap,  */
302     /*  no more drawing to this bitmap is needed until the settings are changed */
303   
304     /*  if we don't have one yet, set up a memory dc for the plot */
305     if (this->m_dcPlot == NULL) 
306     {
307         this->m_dcPlot = CreateCompatibleDC(dc);
308         this->m_bitmapPlot = CreateCompatibleBitmap(dc, this->m_nClientWidth, this->m_nClientHeight);
309         this->m_bitmapOldPlot = SelectObject(this->m_dcPlot, this->m_bitmapPlot);
310     }
311
312     /*  make sure the plot bitmap is cleared */
313     SetBkColor(this->m_dcPlot, this->m_crBackColor);
314     FillRect(this->m_dcPlot, &this->m_rectClient, this->m_brushBack);
315
316     /*  finally, force the plot area to redraw */
317     InvalidateRect(this->m_hParentWnd, &this->m_rectClient, TRUE);
318     ReleaseDC(this->m_hParentWnd, dc);
319 }
320
321 void GraphCtrl_SetRange(TGraphCtrl* this, double dLower, double dUpper, int nDecimalPlaces)
322 {
323     /* ASSERT(dUpper > dLower); */
324     this->m_dLowerLimit     = dLower;
325     this->m_dUpperLimit     = dUpper;
326     this->m_nYDecimals      = nDecimalPlaces;
327     this->m_dRange          = this->m_dUpperLimit - this->m_dLowerLimit;
328     this->m_dVerticalFactor = (double)this->m_nPlotHeight / this->m_dRange;
329     /*  clear out the existing garbage, re-start with a clean plot */
330     GraphCtrl_InvalidateCtrl(this);
331 }
332
333 #if 0
334 void TGraphCtrl::SetXUnits(const char* string)
335 {
336     lstrcpynA(m_strXUnitsString, string, sizeof(m_strXUnitsString));
337     /*  clear out the existing garbage, re-start with a clean plot */
338     InvalidateCtrl();
339 }
340
341 void TGraphCtrl::SetYUnits(const char* string)
342 {
343     lstrcpynA(m_strYUnitsString, string, sizeof(m_strYUnitsString));
344     /*  clear out the existing garbage, re-start with a clean plot */
345     InvalidateCtrl();
346 }
347 #endif
348
349 void GraphCtrl_SetGridColor(TGraphCtrl* this, COLORREF color)
350 {
351     this->m_crGridColor = color;
352     /*  clear out the existing garbage, re-start with a clean plot */
353     GraphCtrl_InvalidateCtrl(this);
354 }
355
356 void GraphCtrl_SetPlotColor(TGraphCtrl* this, int plot, COLORREF color)
357 {
358     this->m_crPlotColor[plot] = color;
359     DeleteObject(this->m_penPlot[plot]);
360     this->m_penPlot[plot] = CreatePen(PS_SOLID, 0, this->m_crPlotColor[plot]);
361     /*  clear out the existing garbage, re-start with a clean plot */
362     GraphCtrl_InvalidateCtrl(this);
363 }
364
365 void GraphCtrl_SetBackgroundColor(TGraphCtrl* this, COLORREF color)
366 {
367     this->m_crBackColor = color;
368     DeleteObject(this->m_brushBack);
369     this->m_brushBack = CreateSolidBrush(this->m_crBackColor);
370     /*  clear out the existing garbage, re-start with a clean plot */
371     GraphCtrl_InvalidateCtrl(this);
372 }
373
374 static void GraphCtrl_DrawPoint(TGraphCtrl* this)
375 {
376     /*  this does the work of "scrolling" the plot to the left
377      *  and appending a new data point all of the plotting is
378      *  directed to the memory based bitmap associated with m_dcPlot
379      *  the will subsequently be BitBlt'd to the client in Paint
380      */
381     int currX, prevX, currY, prevY;
382     HPEN oldPen;
383     RECT rectCleanUp;
384     int i;
385     
386     if (this->m_dcPlot != NULL) 
387     {
388         /*  shift the plot by BitBlt'ing it to itself 
389          *  note: the m_dcPlot covers the entire client
390          *        but we only shift bitmap that is the size 
391          *        of the plot rectangle
392          *  grab the right side of the plot (excluding m_nShiftPixels on the left)
393          *  move this grabbed bitmap to the left by m_nShiftPixels
394          */
395         BitBlt(this->m_dcPlot, this->m_rectPlot.left, this->m_rectPlot.top+1, 
396                this->m_nPlotWidth, this->m_nPlotHeight, this->m_dcPlot, 
397                this->m_rectPlot.left+this->m_nShiftPixels, this->m_rectPlot.top+1, 
398                SRCCOPY);
399
400         /*  establish a rectangle over the right side of plot */
401         /*  which now needs to be cleaned up prior to adding the new point */
402         rectCleanUp = this->m_rectPlot;
403         rectCleanUp.left  = rectCleanUp.right - this->m_nShiftPixels;
404
405         /*  fill the cleanup area with the background */
406         FillRect(this->m_dcPlot, &rectCleanUp, this->m_brushBack);
407
408         /*  draw the next line segment */
409         for (i = 0; i < MAX_PLOTS; i++) 
410         {
411             /*  grab the plotting pen */
412             oldPen = SelectObject(this->m_dcPlot, this->m_penPlot[i]);
413
414             /*  move to the previous point */
415             prevX = this->m_rectPlot.right-this->m_nPlotShiftPixels;
416             prevY = this->m_rectPlot.bottom -
417                 (int)((this->m_dPreviousPosition[i] - this->m_dLowerLimit) * this->m_dVerticalFactor);
418             MoveToEx(this->m_dcPlot, prevX, prevY, NULL);
419
420             /*  draw to the current point */
421             currX = this->m_rectPlot.right-this->m_nHalfShiftPixels;
422             currY = this->m_rectPlot.bottom -
423                 (int)((this->m_dCurrentPosition[i] - this->m_dLowerLimit) * this->m_dVerticalFactor);
424             LineTo(this->m_dcPlot, currX, currY);
425
426             /*  Restore the pen  */
427             SelectObject(this->m_dcPlot, oldPen);
428
429             /*  if the data leaks over the upper or lower plot boundaries
430              *  fill the upper and lower leakage with the background
431              *  this will facilitate clipping on an as needed basis
432              *  as opposed to always calling IntersectClipRect
433              */
434             if ((prevY <= this->m_rectPlot.top) || (currY <= this->m_rectPlot.top)) 
435             {
436                 RECT rc;
437                 rc.bottom = this->m_rectPlot.top+1;
438                 rc.left = prevX;
439                 rc.right = currX+1;
440                 rc.top = this->m_rectClient.top;
441                 FillRect(this->m_dcPlot, &rc, this->m_brushBack);
442             }
443             if ((prevY >= this->m_rectPlot.bottom) || (currY >= this->m_rectPlot.bottom)) 
444             {
445                 RECT rc;
446                 rc.bottom = this->m_rectClient.bottom+1;
447                 rc.left = prevX;
448                 rc.right = currX+1;
449                 rc.top = this->m_rectPlot.bottom+1;
450                 /* RECT rc(prevX, m_rectPlot.bottom+1, currX+1, m_rectClient.bottom+1); */
451                 FillRect(this->m_dcPlot, &rc, this->m_brushBack);
452             }
453
454             /*  store the current point for connection to the next point */
455             this->m_dPreviousPosition[i] = this->m_dCurrentPosition[i];
456         }
457     }
458 }
459
460 double GraphCtrl_AppendPoint(TGraphCtrl* this,
461                              double dNewPoint0, double dNewPoint1,
462                              double dNewPoint2, double dNewPoint3)
463 {
464     /*  append a data point to the plot & return the previous point */
465     double dPrevious;
466
467     dPrevious = this->m_dCurrentPosition[0];
468     this->m_dCurrentPosition[0] = dNewPoint0;
469     this->m_dCurrentPosition[1] = dNewPoint1;
470     this->m_dCurrentPosition[2] = dNewPoint2;
471     this->m_dCurrentPosition[3] = dNewPoint3;
472     GraphCtrl_DrawPoint(this);
473     /* Invalidate(); */
474     return dPrevious;
475 }
476
477 static void GraphCtrl_Paint(TGraphCtrl* this, HWND hWnd, HDC dc)
478 {
479     HDC memDC;
480     HBITMAP memBitmap;
481     HBITMAP oldBitmap; /*  bitmap originally found in CMemDC */
482
483 /*   RECT rcClient; */
484 /*   GetClientRect(hWnd, &rcClient); */
485 /*   FillSolidRect(dc, &rcClient, RGB(255, 0, 255)); */
486 /*   m_nClientWidth = rcClient.right - rcClient.left; */
487 /*   m_nClientHeight = rcClient.bottom - rcClient.top; */
488
489     /*  no real plotting work is performed here,  */
490     /*  just putting the existing bitmaps on the client */
491
492     /*  to avoid flicker, establish a memory dc, draw to it */
493     /*  and then BitBlt it to the client */
494     memDC = CreateCompatibleDC(dc);
495     memBitmap = CreateCompatibleBitmap(dc, this->m_nClientWidth, this->m_nClientHeight);
496     oldBitmap = SelectObject(memDC, memBitmap);
497
498     if (memDC != NULL)
499     {
500         /*  first drop the grid on the memory dc */
501         BitBlt(memDC, 0, 0, this->m_nClientWidth, this->m_nClientHeight, this->m_dcGrid, 0, 0, SRCCOPY);
502         /*  now add the plot on top as a "pattern" via SRCPAINT. */
503         /*  works well with dark background and a light plot */
504         BitBlt(memDC, 0, 0, this->m_nClientWidth, this->m_nClientHeight, this->m_dcPlot, 0, 0, SRCPAINT);  /* SRCPAINT */
505         /*  finally send the result to the display */
506         BitBlt(dc, 0, 0, this->m_nClientWidth, this->m_nClientHeight, memDC, 0, 0, SRCCOPY);
507     }
508     SelectObject(memDC, oldBitmap);
509     DeleteObject(memBitmap);
510     DeleteDC(memDC);
511 }
512
513 #if 0
514 void TGraphCtrl::Reset(void)
515 {
516     /*  to clear the existing data (in the form of a bitmap) */
517     /*  simply invalidate the entire control */
518     InvalidateCtrl();
519 }
520 #endif
521
522 extern TGraphCtrl PerformancePageCpuUsageHistoryGraph;
523 extern TGraphCtrl PerformancePageMemUsageHistoryGraph;
524 extern HWND hPerformancePageCpuUsageHistoryGraph;
525 extern HWND hPerformancePageMemUsageHistoryGraph;
526
527 INT_PTR CALLBACK
528 GraphCtrl_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
529 {
530     RECT        rcClient;
531     HDC            hdc;
532     PAINTSTRUCT     ps;
533     
534     switch (message) 
535     {
536     case WM_ERASEBKGND:
537         return TRUE;
538     /* 
539      *  Filter out mouse  & keyboard messages
540      */ 
541     /* case WM_APPCOMMAND: */
542     case WM_CAPTURECHANGED:
543     case WM_LBUTTONDBLCLK:
544     case WM_LBUTTONDOWN:
545     case WM_LBUTTONUP:
546     case WM_MBUTTONDBLCLK:
547     case WM_MBUTTONDOWN:
548     case WM_MBUTTONUP:
549     case WM_MOUSEACTIVATE:
550     case WM_MOUSEHOVER:
551     case WM_MOUSELEAVE:
552     case WM_MOUSEMOVE:
553     /* case WM_MOUSEWHEEL: */
554     case WM_NCHITTEST:
555     case WM_NCLBUTTONDBLCLK:
556     case WM_NCLBUTTONDOWN:
557     case WM_NCLBUTTONUP:
558     case WM_NCMBUTTONDBLCLK:
559     case WM_NCMBUTTONDOWN:
560     case WM_NCMBUTTONUP:
561     /* case WM_NCMOUSEHOVER: */
562     /* case WM_NCMOUSELEAVE: */
563     case WM_NCMOUSEMOVE:
564     case WM_NCRBUTTONDBLCLK:
565     case WM_NCRBUTTONDOWN:
566     case WM_NCRBUTTONUP:
567     /* case WM_NCXBUTTONDBLCLK: */
568     /* case WM_NCXBUTTONDOWN: */
569     /* case WM_NCXBUTTONUP: */
570     case WM_RBUTTONDBLCLK:
571     case WM_RBUTTONDOWN:
572     case WM_RBUTTONUP:
573     /* case WM_XBUTTONDBLCLK: */
574     /* case WM_XBUTTONDOWN: */
575     /* case WM_XBUTTONUP: */
576     case WM_ACTIVATE:
577     case WM_CHAR:
578     case WM_DEADCHAR:
579     case WM_GETHOTKEY:
580     case WM_HOTKEY:
581     case WM_KEYDOWN:
582     case WM_KEYUP:
583     case WM_KILLFOCUS:
584     case WM_SETFOCUS:
585     case WM_SETHOTKEY:
586     case WM_SYSCHAR:
587     case WM_SYSDEADCHAR:
588     case WM_SYSKEYDOWN:
589     case WM_SYSKEYUP:
590         return 0;
591
592     case WM_NCCALCSIZE:
593         return 0;
594
595     case WM_SIZE:
596         if (hWnd == hPerformancePageMemUsageHistoryGraph) 
597         {
598             GraphCtrl_Resize(&PerformancePageMemUsageHistoryGraph);
599             GraphCtrl_InvalidateCtrl(&PerformancePageMemUsageHistoryGraph);
600         }
601         if (hWnd == hPerformancePageCpuUsageHistoryGraph) 
602         {
603             GraphCtrl_Resize(&PerformancePageCpuUsageHistoryGraph);
604             GraphCtrl_InvalidateCtrl(&PerformancePageCpuUsageHistoryGraph);
605         }
606         return 0;
607
608     case WM_PAINT:
609         hdc = BeginPaint(hWnd, &ps);
610         GetClientRect(hWnd, &rcClient);
611         if (hWnd == hPerformancePageMemUsageHistoryGraph)
612             GraphCtrl_Paint(&PerformancePageMemUsageHistoryGraph, hWnd, hdc);
613         if (hWnd == hPerformancePageCpuUsageHistoryGraph)
614             GraphCtrl_Paint(&PerformancePageCpuUsageHistoryGraph, hWnd, hdc);
615         EndPaint(hWnd, &ps);
616         return 0;
617     }
618     
619     /* 
620      *  We pass on all non-handled messages
621      */ 
622     return CallWindowProcW(OldGraphCtrlWndProc, hWnd, message, wParam, lParam);
623 }