https://git.reactos.org/?p=reactos.git;a=commitdiff;h=403222dd4f73836b38c11…
commit 403222dd4f73836b38c11a42fa6c3fc1614681d7
Author:     Valerij Zaporogeci <vlrzprgts(a)gmail.com>
AuthorDate: Mon Dec 6 04:49:42 2021 +0200
Commit:     Stanislav Motylkov <x86corez(a)gmail.com>
CommitDate: Thu Dec 16 03:06:09 2021 +0300
    [TASKMGR] Preserve graphs history on resizes (#4141)
    - Also the graph stays preserved on the kernel time toggle
    - An attempt to clean up the collected cruft was made as well
---
 base/applications/taskmgr/graphctl.c | 781 ++++++++++++-----------------------
 base/applications/taskmgr/graphctl.h | 118 ++----
 base/applications/taskmgr/perfpage.c |  78 ++--
 3 files changed, 338 insertions(+), 639 deletions(-)
diff --git a/base/applications/taskmgr/graphctl.c b/base/applications/taskmgr/graphctl.c
index de60958ef02..0d15f4d61d8 100644
--- a/base/applications/taskmgr/graphctl.c
+++ b/base/applications/taskmgr/graphctl.c
@@ -12,582 +12,294 @@
 WNDPROC OldGraphCtrlWndProc;
-static void GraphCtrl_Init(TGraphCtrl* this)
+BOOL
+GraphCtrl_Create(PTM_GRAPH_CONTROL inst, HWND hWnd, HWND hParentWnd, PTM_FORMAT fmt)
 {
-    int i;
-
-    this->m_hWnd = 0;
-    this->m_hParentWnd = 0;
-    this->m_dcGrid = 0;
-    this->m_dcPlot = 0;
-    this->m_bitmapOldGrid = 0;
-    this->m_bitmapOldPlot = 0;
-    this->m_bitmapGrid = 0;
-    this->m_bitmapPlot = 0;
-    this->m_brushBack = 0;
-
-    this->m_penPlot[0] = 0;
-    this->m_penPlot[1] = 0;
-    this->m_penPlot[2] = 0;
-    this->m_penPlot[3] = 0;
-
-    /* since plotting is based on a LineTo for each new point
-     * we need a starting point (i.e. a "previous" point)
-     * use 0.0 as the default first point.
-     * these are public member variables, and can be changed outside
-     * (after construction).  Therefore m_perviousPosition could be set to
-     * a more appropriate value prior to the first call to SetPosition.
-     */
-    this->m_dPreviousPosition[0] = 0.0;
-    this->m_dPreviousPosition[1] = 0.0;
-    this->m_dPreviousPosition[2] = 0.0;
-    this->m_dPreviousPosition[3] = 0.0;
-
-    /*  public variable for the number of decimal places on the y axis */
-    this->m_nYDecimals = 3;
-
-    /*  set some initial values for the scaling until "SetRange" is called.
-     *  these are protected variables and must be set with SetRange
-     *  in order to ensure that m_dRange is updated accordingly
-     */
-    /*   m_dLowerLimit = -10.0; */
-    /*   m_dUpperLimit =  10.0; */
-    this->m_dLowerLimit = 0.0;
-    this->m_dUpperLimit = 100.0;
-    this->m_dRange      =  this->m_dUpperLimit - this->m_dLowerLimit;  /*
protected member variable */
-
-    /*  m_nShiftPixels determines how much the plot shifts (in terms of pixels)  */
-    /*  with the addition of a new data point */
-    this->m_nShiftPixels     = 4;
-    this->m_nHalfShiftPixels = this->m_nShiftPixels / 2;  /*  protected */
-    this->m_nPlotShiftPixels = this->m_nShiftPixels + this->m_nHalfShiftPixels;
/*  protected */
-
-    /*  Set how big the grid boxes are  */
-    this->m_nGridXPixels = 12;
-    this->m_nGridYPixels = 12;
-
-    /*  Task manager should scroll grid with the graph. This variable contains the  */
-    /*  amount of pixels the grid paint origin should shift to left  */
-    this->m_nGridOffsetPixels = 0;
-
-    /*  background, grid and data colors */
-    /*  these are public variables and can be set directly */
-    this->m_crBackColor = RGB(  0,   0,   0);  /*  see also SetBackgroundColor */
-    this->m_crGridColor = RGB(  0, 128,  64);  /*  see also SetGridColor */
-    this->m_crPlotColor[0] = RGB(255, 255, 255);  /*  see also SetPlotColor */
-    this->m_crPlotColor[1] = RGB(100, 255, 255);  /*  see also SetPlotColor */
-    this->m_crPlotColor[2] = RGB(255, 100, 255);  /*  see also SetPlotColor */
-    this->m_crPlotColor[3] = RGB(255, 255, 100);  /*  see also SetPlotColor */
-
-    /*  protected variables */
-    for (i = 0; i < MAX_PLOTS; i++)
+    HDC     hdc, hdcg;
+    HBITMAP hbmOld;
+    UINT    Size;
+    INT     p;
+    RECT    rc;
+
+    inst->hParentWnd = hParentWnd;
+    inst->hWnd = hWnd;
+
+    Size = GetSystemMetrics(SM_CXSCREEN);
+    inst->BitmapWidth = Size;
+    Size /= PLOT_SHIFT;
+    inst->PointBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Size *
NUM_PLOTS);
+    if (!inst->PointBuffer)
     {
-        this->m_penPlot[i] = CreatePen(PS_SOLID, 0, this->m_crPlotColor[i]);
+        goto fail;
     }
-    this->m_brushBack = CreateSolidBrush(this->m_crBackColor);
-    /*  public member variables, can be set directly  */
-    strcpy(this->m_strXUnitsString, "Samples");  /*  can also be set with
SetXUnits */
-    strcpy(this->m_strYUnitsString, "Y units");  /*  can also be set with
SetYUnits */
+    inst->NumberOfPoints = Size;
+    inst->CurrIndex = 0;
-    /*  protected bitmaps to restore the memory DC's */
-    this->m_bitmapOldGrid = NULL;
-    this->m_bitmapOldPlot = NULL;
-}
+    /* Styling */
+    inst->hPenGrid = CreatePen(PS_SOLID, 0, fmt->clrGrid);
+    inst->hPen0 = CreatePen(PS_SOLID, 0, fmt->clrPlot0);
+    inst->hPen1 = CreatePen(PS_SOLID, 0, fmt->clrPlot1);
+    inst->hBrushBack = CreateSolidBrush(fmt->clrBack);
-void GraphCtrl_Dispose(TGraphCtrl* this)
-{
-    int plot;
+    if (!inst->hPenGrid ||
+        !inst->hPen0 ||
+        !inst->hPen1 ||
+        !inst->hBrushBack)
+    {
+        goto fail;
+    }
-    for (plot = 0; plot < MAX_PLOTS; plot++)
-        DeleteObject(this->m_penPlot[plot]);
+    if (fmt->GridCellWidth >= PLOT_SHIFT << 2)
+        inst->GridCellWidth = fmt->GridCellWidth;
+    else
+        inst->GridCellWidth = PLOT_SHIFT << 2;
+    if (fmt->GridCellHeight >= PLOT_SHIFT << 2)
+        inst->GridCellHeight = fmt->GridCellHeight;
+    else
+        inst->GridCellHeight = PLOT_SHIFT << 2;
+
+    inst->DrawSecondaryPlot = fmt->DrawSecondaryPlot;
+
+    GetClientRect(hWnd, &rc);
+    inst->BitmapHeight = rc.bottom;
+    inst->ftPixelsPerPercent = (FLOAT)(inst->BitmapHeight) / 100.00f;
+
+    hdc = GetDC(hParentWnd);
+    hdcg = CreateCompatibleDC(hdc);
+    inst->hdcGraph = hdcg;
+    inst->hbmGraph = CreateCompatibleBitmap(hdc, inst->BitmapWidth,
inst->BitmapHeight);
+
+    if (!hdc ||
+        !hdcg ||
+        !inst->hbmGraph)
+    {
+        goto fail;
+    }
-    /*  just to be picky restore the bitmaps for the two memory dc's */
-    /*  (these dc's are being destroyed so there shouldn't be any leaks) */
+    ReleaseDC(hParentWnd, hdc);
+    hbmOld = (HBITMAP)SelectObject(hdcg, inst->hbmGraph);
+    DeleteObject(hbmOld);
-    if (this->m_bitmapOldGrid != NULL) SelectObject(this->m_dcGrid,
this->m_bitmapOldGrid);
-    if (this->m_bitmapOldPlot != NULL) SelectObject(this->m_dcPlot,
this->m_bitmapOldPlot);
-    if (this->m_bitmapGrid    != NULL) DeleteObject(this->m_bitmapGrid);
-    if (this->m_bitmapPlot    != NULL) DeleteObject(this->m_bitmapPlot);
-    if (this->m_dcGrid        != NULL) DeleteDC(this->m_dcGrid);
-    if (this->m_dcPlot        != NULL) DeleteDC(this->m_dcPlot);
-    if (this->m_brushBack     != NULL) DeleteObject(this->m_brushBack);
-}
+    SetBkColor(hdcg, fmt->clrBack);
+    rc.right = inst->BitmapWidth;
+    FillRect(hdcg, &rc, inst->hBrushBack);
-void GraphCtrl_Create(TGraphCtrl* this, HWND hWnd, HWND hParentWnd, UINT nID)
-{
-    GraphCtrl_Init(this);
-    this->m_hParentWnd = hParentWnd;
-    this->m_hWnd = hWnd;
+    inst->CurrShift = 0;
+    SelectObject(hdcg, inst->hPenGrid);
+    for (p = inst->GridCellHeight - 1;
+         p < inst->BitmapHeight;
+         p += inst->GridCellHeight)
+    {
+        MoveToEx(hdcg, 0, p, NULL);
+        LineTo(hdcg, inst->BitmapWidth, p);
+    }
+    for (p = inst->BitmapWidth - 1;
+         p > 0;
+         p -= inst->GridCellWidth)
+    {
+        MoveToEx(hdcg, p, 0, NULL);
+        LineTo(hdcg, p, inst->BitmapHeight);
+    }
+    SelectObject(hdcg, inst->hPen0);
-    GraphCtrl_Resize(this);
+    return TRUE;
-    return;
+fail:
+    GraphCtrl_Dispose(inst);
+    return FALSE;
 }
-void GraphCtrl_SetRange(TGraphCtrl* this, double dLower, double dUpper, int
nDecimalPlaces)
+void
+GraphCtrl_Dispose(PTM_GRAPH_CONTROL inst)
 {
-    /* ASSERT(dUpper > dLower); */
-    this->m_dLowerLimit     = dLower;
-    this->m_dUpperLimit     = dUpper;
-    this->m_nYDecimals      = nDecimalPlaces;
-    this->m_dRange          = this->m_dUpperLimit - this->m_dLowerLimit;
-    this->m_dVerticalFactor = (double)this->m_nPlotHeight / this->m_dRange;
-    /*  clear out the existing garbage, re-start with a clean plot */
-    GraphCtrl_InvalidateCtrl(this, FALSE);
-}
+    if (inst->PointBuffer)
+        HeapFree(GetProcessHeap(), 0, inst->PointBuffer);
-#if 0
-void TGraphCtrl::SetXUnits(const char* string)
-{
-    strncpy(m_strXUnitsString, string, sizeof(m_strXUnitsString) - 1);
-    /*  clear out the existing garbage, re-start with a clean plot */
-    InvalidateCtrl();
-}
+    if (inst->hPenGrid)
+        DeleteObject(inst->hPenGrid);
-void TGraphCtrl::SetYUnits(const char* string)
-{
-    strncpy(m_strYUnitsString, string, sizeof(m_strYUnitsString) - 1);
-    /*  clear out the existing garbage, re-start with a clean plot */
-    InvalidateCtrl();
-}
-#endif
+    if (inst->hPen0)
+        DeleteObject(inst->hPen0);
-void GraphCtrl_SetGridColor(TGraphCtrl* this, COLORREF color)
-{
-    this->m_crGridColor = color;
-    /*  clear out the existing garbage, re-start with a clean plot */
-    GraphCtrl_InvalidateCtrl(this, FALSE);
-}
+    if (inst->hPen1)
+        DeleteObject(inst->hPen1);
-void GraphCtrl_SetPlotColor(TGraphCtrl* this, int plot, COLORREF color)
-{
-    this->m_crPlotColor[plot] = color;
-    DeleteObject(this->m_penPlot[plot]);
-    this->m_penPlot[plot] = CreatePen(PS_SOLID, 0, this->m_crPlotColor[plot]);
-    /*  clear out the existing garbage, re-start with a clean plot */
-    GraphCtrl_InvalidateCtrl(this, FALSE);
-}
+    if (inst->hBrushBack)
+        DeleteObject(inst->hBrushBack);
-void GraphCtrl_SetBackgroundColor(TGraphCtrl* this, COLORREF color)
-{
-    this->m_crBackColor = color;
-    DeleteObject(this->m_brushBack);
-    this->m_brushBack = CreateSolidBrush(this->m_crBackColor);
-    /*  clear out the existing garbage, re-start with a clean plot */
-    GraphCtrl_InvalidateCtrl(this, FALSE);
+    if (inst->hbmGraph)
+        DeleteObject(inst->hbmGraph);
+
+    if (inst->hdcGraph)
+        DeleteObject(inst->hdcGraph);
 }
-void GraphCtrl_InvalidateCtrl(TGraphCtrl* this, BOOL bResize)
+void
+GraphCtrl_AddPoint(PTM_GRAPH_CONTROL inst, BYTE val0, BYTE val1)
 {
-    /*  There is a lot of drawing going on here - particularly in terms of  */
-    /*  drawing the grid.  Don't panic, this is all being drawn (only once) */
-    /*  to a bitmap.  The result is then BitBlt'd to the control whenever needed. */
-    int i;
-    int nCharacters;
-    //int nTopGridPix, nMidGridPix, nBottomGridPix;
-
-    HPEN oldPen;
-    HPEN solidPen = CreatePen(PS_SOLID, 0, this->m_crGridColor);
-    /* HFONT axisFont, yUnitFont, oldFont; */
-    /* char strTemp[50]; */
-
-    /*  in case we haven't established the memory dc's */
-    /* CClientDC dc(this); */
-    HDC dc = GetDC(this->m_hParentWnd);
-
-    /*  if we don't have one yet, set up a memory dc for the grid */
-    if (this->m_dcGrid == NULL)
+    HDC    hdcg;
+    PBYTE  t;
+    RECT   rcDirt;
+
+    UINT   Prev0, Prev1, RetainingWidth;
+    INT    PrevY, CurrY, p, v;
+
+    hdcg = inst->hdcGraph;
+    RetainingWidth = inst->BitmapWidth - PLOT_SHIFT;
+    t = inst->PointBuffer;
+    Prev0 = *(t + inst->CurrIndex);
+    Prev1 = *(t + inst->CurrIndex + inst->NumberOfPoints);
+    if (inst->CurrIndex < inst->NumberOfPoints)
     {
-        this->m_dcGrid = CreateCompatibleDC(dc);
-        this->m_bitmapGrid = CreateCompatibleBitmap(dc, this->m_nClientWidth,
this->m_nClientHeight);
-        this->m_bitmapOldGrid = (HBITMAP)SelectObject(this->m_dcGrid,
this->m_bitmapGrid);
+        inst->CurrIndex++;
     }
-    else if(bResize)
+    else
     {
-        // the size of the drawing area has changed
-        // so create a new bitmap of the appropriate size
-        if(this->m_bitmapGrid != NULL)
-        {
-            this->m_bitmapGrid = (HBITMAP)SelectObject(this->m_dcGrid,
this->m_bitmapOldGrid);
-            DeleteObject(this->m_bitmapGrid);
-            this->m_bitmapGrid = CreateCompatibleBitmap(dc, this->m_nClientWidth,
this->m_nClientHeight);
-            SelectObject(this->m_dcGrid, this->m_bitmapGrid);
-        }
+        inst->CurrIndex = 0;
     }
-
-    SetBkColor(this->m_dcGrid, this->m_crBackColor);
-
-    /*  fill the grid background */
-    FillRect(this->m_dcGrid, &this->m_rectClient, this->m_brushBack);
-
-    /*  draw the plot rectangle: */
-    /*  determine how wide the y axis scaling values are */
-    nCharacters = abs((int)log10(fabs(this->m_dUpperLimit)));
-    nCharacters = max(nCharacters, abs((int)log10(fabs(this->m_dLowerLimit))));
-
-    /*  add the units digit, decimal point and a minus sign, and an extra space */
-    /*  as well as the number of decimal places to display */
-    nCharacters = nCharacters + 4 + this->m_nYDecimals;
-
-    /*  adjust the plot rectangle dimensions */
-    /*  assume 6 pixels per character (this may need to be adjusted) */
-    /*   m_rectPlot.left = m_rectClient.left + 6*(nCharacters); */
-    this->m_rectPlot.left = this->m_rectClient.left;
-    this->m_nPlotWidth    = this->m_rectPlot.right - this->m_rectPlot.left;/*
m_rectPlot.Width(); */
-
-    /*  draw the plot rectangle */
-    oldPen = (HPEN)SelectObject(this->m_dcGrid, solidPen);
-    MoveToEx(this->m_dcGrid, this->m_rectPlot.left, this->m_rectPlot.top, NULL);
-    LineTo(this->m_dcGrid, this->m_rectPlot.right + 1, this->m_rectPlot.top);
-    LineTo(this->m_dcGrid, this->m_rectPlot.right + 1, this->m_rectPlot.bottom +
1);
-    LineTo(this->m_dcGrid, this->m_rectPlot.left, this->m_rectPlot.bottom + 1);
-    /*   LineTo(m_dcGrid, m_rectPlot.left, m_rectPlot.top); */
-
-    /*  draw the horizontal axis */
-    for (i = this->m_rectPlot.top; i <= this->m_rectPlot.bottom; i +=
this->m_nGridYPixels)
+    *(t + inst->CurrIndex) = val0;
+    *(t + inst->CurrIndex + inst->NumberOfPoints) = val1;
+
+    /* Drawing points, first shifting the plot left */
+    BitBlt(hdcg, 0, 0, RetainingWidth, inst->BitmapHeight, hdcg, PLOT_SHIFT, 0,
SRCCOPY);
+
+    rcDirt.left = RetainingWidth;
+    rcDirt.top = 0;
+    rcDirt.right = inst->BitmapWidth;
+    rcDirt.bottom = inst->BitmapHeight;
+    FillRect(hdcg, &rcDirt, inst->hBrushBack);
+
+    SelectObject(hdcg, inst->hPenGrid);
+    for (p = inst->GridCellHeight - 1;
+         p < inst->BitmapHeight;
+         p += inst->GridCellHeight)
     {
-        MoveToEx(this->m_dcGrid, this->m_rectPlot.left, i, NULL);
-        LineTo(this->m_dcGrid, this->m_rectPlot.right, i);
+        MoveToEx(hdcg, RetainingWidth, p, NULL);
+        LineTo(hdcg, inst->BitmapWidth, p);
     }
-
-    /*  draw the vertical axis */
-    /*  In order to keep grid position uniform when resizing, vertical axis should be  */
-    /*  drawn from right to left  */
-    for (i = this->m_rectPlot.right - this->m_nGridOffsetPixels; i >=
this->m_rectPlot.left; i -= this->m_nGridXPixels)
+    v = inst->CurrShift + PLOT_SHIFT;
+    if (v >= inst->GridCellWidth)
     {
-        MoveToEx(this->m_dcGrid, i, this->m_rectPlot.bottom, NULL);
-        LineTo(this->m_dcGrid, i, this->m_rectPlot.top);
+        v -= inst->GridCellWidth;
+        p = inst->BitmapWidth - v - 1;
+        MoveToEx(hdcg, p, 0, NULL);
+        LineTo(hdcg, p, inst->BitmapHeight);
     }
+    inst->CurrShift = v;
-    SelectObject(this->m_dcGrid, oldPen);
-    DeleteObject(solidPen);
-
-#if 0
-    /*  create some fonts (horizontal and vertical) */
-    /*  use a height of 14 pixels and 300 weight  */
-    /*  (these may need to be adjusted depending on the display) */
-    axisFont = CreateFont (14, 0, 0, 0, 300,
-                           FALSE, FALSE, 0, ANSI_CHARSET,
-                           OUT_DEFAULT_PRECIS,
-                           CLIP_DEFAULT_PRECIS,
-                           DEFAULT_QUALITY,
-                           DEFAULT_PITCH|FF_SWISS, "Arial");
-    yUnitFont = CreateFont (14, 0, 900, 0, 300,
-                            FALSE, FALSE, 0, ANSI_CHARSET,
-                            OUT_DEFAULT_PRECIS,
-                            CLIP_DEFAULT_PRECIS,
-                            DEFAULT_QUALITY,
-                            DEFAULT_PITCH|FF_SWISS, "Arial");
-
-    /*  grab the horizontal font */
-    oldFont = (HFONT)SelectObject(m_dcGrid, axisFont);
-
-    /*  y max */
-    SetTextColor(m_dcGrid, m_crGridColor);
-    SetTextAlign(m_dcGrid, TA_RIGHT|TA_TOP);
-    sprintf(strTemp, "%.*lf", m_nYDecimals, m_dUpperLimit);
-    TextOut(m_dcGrid, m_rectPlot.left-4, m_rectPlot.top, strTemp, wcslen(strTemp));
-
-    /*  y min */
-    SetTextAlign(m_dcGrid, TA_RIGHT|TA_BASELINE);
-    sprintf(strTemp, "%.*lf", m_nYDecimals, m_dLowerLimit);
-    TextOut(m_dcGrid, m_rectPlot.left-4, m_rectPlot.bottom, strTemp, wcslen(strTemp));
-
-    /*  x min */
-    SetTextAlign(m_dcGrid, TA_LEFT|TA_TOP);
-    TextOut(m_dcGrid, m_rectPlot.left, m_rectPlot.bottom+4, "0", 1);
-
-    /*  x max */
-    SetTextAlign(m_dcGrid, TA_RIGHT|TA_TOP);
-    sprintf(strTemp, "%d", m_nPlotWidth/m_nShiftPixels);
-    TextOut(m_dcGrid, m_rectPlot.right, m_rectPlot.bottom+4, strTemp, wcslen(strTemp));
-
-    /*  x units */
-    SetTextAlign(m_dcGrid, TA_CENTER|TA_TOP);
-    TextOut(m_dcGrid, (m_rectPlot.left+m_rectPlot.right)/2,
-            m_rectPlot.bottom+4, m_strXUnitsString, wcslen(m_strXUnitsString));
-
-    /*  restore the font */
-    SelectObject(m_dcGrid, oldFont);
-
-    /*  y units */
-    oldFont = (HFONT)SelectObject(m_dcGrid, yUnitFont);
-    SetTextAlign(m_dcGrid, TA_CENTER|TA_BASELINE);
-    TextOut(m_dcGrid, (m_rectClient.left+m_rectPlot.left)/2,
-            (m_rectPlot.bottom+m_rectPlot.top)/2, m_strYUnitsString,
wcslen(m_strYUnitsString));
-    SelectObject(m_dcGrid, oldFont);
-#endif
-    /*  at this point we are done filling the grid bitmap,  */
-    /*  no more drawing to this bitmap is needed until the settings are changed */
-
-    /*  if we don't have one yet, set up a memory dc for the plot */
-    if (this->m_dcPlot == NULL)
-    {
-        this->m_dcPlot = CreateCompatibleDC(dc);
-        this->m_bitmapPlot = CreateCompatibleBitmap(dc, this->m_nClientWidth,
this->m_nClientHeight);
-        this->m_bitmapOldPlot = (HBITMAP)SelectObject(this->m_dcPlot,
this->m_bitmapPlot);
-    }
-    else if(bResize)
+    if (inst->DrawSecondaryPlot)
     {
-        // the size of the drawing area has changed
-        // so create a new bitmap of the appropriate size
-        if(this->m_bitmapPlot != NULL)
-        {
-            this->m_bitmapPlot = (HBITMAP)SelectObject(this->m_dcPlot,
this->m_bitmapOldPlot);
-            DeleteObject(this->m_bitmapPlot);
-            this->m_bitmapPlot = CreateCompatibleBitmap(dc, this->m_nClientWidth,
this->m_nClientHeight);
-            SelectObject(this->m_dcPlot, this->m_bitmapPlot);
-            GraphCtrl_DrawPoint(this);
-        }
-    }
-
-    /*  make sure the plot bitmap is cleared */
-    SetBkColor(this->m_dcPlot, this->m_crBackColor);
-    FillRect(this->m_dcPlot, &this->m_rectClient, this->m_brushBack);
+        SelectObject(inst->hdcGraph, inst->hPen1);
-    /*  finally, force the plot area to redraw */
-    InvalidateRect(this->m_hParentWnd, &this->m_rectClient, TRUE);
-    ReleaseDC(this->m_hParentWnd, dc);
-}
+        PrevY = inst->BitmapHeight - Prev1 * inst->ftPixelsPerPercent;
+        MoveToEx(inst->hdcGraph, RetainingWidth - 1, PrevY, NULL);
+        CurrY = inst->BitmapHeight - val1 * inst->ftPixelsPerPercent;
+        LineTo(inst->hdcGraph, inst->BitmapWidth - 1, CurrY);
+    }
-double GraphCtrl_AppendPoint(TGraphCtrl* this,
-                             double dNewPoint0, double dNewPoint1,
-                             double dNewPoint2, double dNewPoint3)
-{
-    /*  append a data point to the plot & return the previous point */
-    double dPrevious;
-
-    dPrevious = this->m_dCurrentPosition[0];
-    this->m_dCurrentPosition[0] = dNewPoint0;
-    this->m_dCurrentPosition[1] = dNewPoint1;
-    this->m_dCurrentPosition[2] = dNewPoint2;
-    this->m_dCurrentPosition[3] = dNewPoint3;
-    GraphCtrl_ShiftGrid(this);
-    GraphCtrl_DrawPoint(this);
-    /* Invalidate(); */
-    return dPrevious;
+    SelectObject(inst->hdcGraph, inst->hPen0);
+    PrevY = inst->BitmapHeight - Prev0 * inst->ftPixelsPerPercent;
+    MoveToEx(inst->hdcGraph, RetainingWidth - 1, PrevY, NULL);
+    CurrY = inst->BitmapHeight - val0 * inst->ftPixelsPerPercent;
+    LineTo(inst->hdcGraph, inst->BitmapWidth - 1, CurrY);
 }
-void GraphCtrl_Paint(TGraphCtrl* this, HWND hWnd, HDC dc)
+inline void
+GraphCtrl_RedrawBitmap(PTM_GRAPH_CONTROL inst, INT h)
 {
-    HDC memDC;
-    HBITMAP memBitmap;
-    HBITMAP oldBitmap; /*  bitmap originally found in CMemDC */
-
-/*   RECT rcClient; */
-/*   GetClientRect(hWnd, &rcClient); */
-/*   FillSolidRect(dc, &rcClient, RGB(255, 0, 255)); */
-/*   m_nClientWidth = rcClient.right - rcClient.left; */
-/*   m_nClientHeight = rcClient.bottom - rcClient.top; */
-
-    /*  no real plotting work is performed here,  */
-    /*  just putting the existing bitmaps on the client */
-
-    /*  to avoid flicker, establish a memory dc, draw to it */
-    /*  and then BitBlt it to the client */
-    memDC = CreateCompatibleDC(dc);
-    memBitmap = (HBITMAP)CreateCompatibleBitmap(dc, this->m_nClientWidth,
this->m_nClientHeight);
-    oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap);
-
-    if (memDC != NULL)
+    HDC    hdcg;
+    PBYTE  t;
+    RECT   rc;
+    INT    i, j, y, x, p;
+    FLOAT  coef;
+
+    hdcg = inst->hdcGraph;
+    rc.left = 0; rc.top = 0;
+    rc.right = inst->BitmapWidth; rc.bottom = h;
+    FillRect(hdcg, &rc, inst->hBrushBack);
+
+    SelectObject(hdcg, inst->hPenGrid);
+
+    for (p = inst->GridCellHeight - 1;
+         p < inst->BitmapHeight;
+         p += inst->GridCellHeight)
     {
-        /*  first drop the grid on the memory dc */
-        BitBlt(memDC, 0, 0, this->m_nClientWidth, this->m_nClientHeight,
this->m_dcGrid, 0, 0, SRCCOPY);
-        /*  now add the plot on top as a "pattern" via SRCPAINT. */
-        /*  works well with dark background and a light plot */
-        BitBlt(memDC, 0, 0, this->m_nClientWidth, this->m_nClientHeight,
this->m_dcPlot, 0, 0, SRCPAINT);  /* SRCPAINT */
-        /*  finally send the result to the display */
-        BitBlt(dc, 0, 0, this->m_nClientWidth, this->m_nClientHeight, memDC, 0, 0,
SRCCOPY);
+        MoveToEx(hdcg, 0, p, NULL);
+        LineTo(hdcg, inst->BitmapWidth, p);
     }
-    SelectObject(memDC, oldBitmap);
-    DeleteObject(memBitmap);
-    DeleteDC(memDC);
-}
-
-void GraphCtrl_ShiftGrid(TGraphCtrl* this)
-{
-    RECT rectCleanUp;
-    HPEN oldPen, solidPen;
-    int i;
-
-    if (this->m_dcGrid == NULL)
-        return;
-
-    solidPen = CreatePen(PS_SOLID, 0, this->m_crGridColor);
-
-    /* Scroll the grid left: BitBlt it to itself */
-    BitBlt(this->m_dcGrid, this->m_rectPlot.left, this->m_rectPlot.top + 1,
-           this->m_nPlotWidth, this->m_nPlotHeight,
-           this->m_dcGrid, this->m_rectPlot.left + this->m_nShiftPixels,
this->m_rectPlot.top + 1,
-           SRCCOPY);
-
-    /* Set shift pixels */
-    this->m_nGridOffsetPixels = (this->m_nGridOffsetPixels +
this->m_nShiftPixels) % this->m_nGridXPixels;
-
-    /* Construct a rect in which needs update */
-    rectCleanUp = this->m_rectPlot;
-    rectCleanUp.left = rectCleanUp.right - this->m_nShiftPixels;
-    /* Fill the cleanup area with the background */
-    FillRect(this->m_dcGrid, &rectCleanUp, this->m_brushBack);
-
-    /* Draw the plot rectangle */
-    oldPen = (HPEN)SelectObject(this->m_dcGrid, solidPen);
-
-    /* Redraw horizontal axis */
-    for (i = rectCleanUp.top; i < rectCleanUp.bottom; i += this->m_nGridYPixels)
+    for (p = inst->BitmapWidth - inst->CurrShift - 1;
+         p > 0;
+         p -= inst->GridCellWidth)
     {
-        MoveToEx(this->m_dcGrid, rectCleanUp.left, i, NULL);
-        LineTo(this->m_dcGrid, rectCleanUp.right, i);
+        MoveToEx(hdcg, p, 0, NULL);
+        LineTo(hdcg, p, inst->BitmapHeight);
     }
-    /* Redraw scrolled vertical axis */
-    MoveToEx(this->m_dcGrid, rectCleanUp.right - this->m_nGridOffsetPixels,
rectCleanUp.top, NULL);
-    LineTo(this->m_dcGrid, rectCleanUp.right - this->m_nGridOffsetPixels,
rectCleanUp.bottom);
-
-    SelectObject(this->m_dcGrid, oldPen);
-    DeleteObject(solidPen);
-}
+    coef = inst->ftPixelsPerPercent;
-void GraphCtrl_DrawPoint(TGraphCtrl* this)
-{
-    /*  this does the work of "scrolling" the plot to the left
-     *  and appending a new data point all of the plotting is
-     *  directed to the memory based bitmap associated with m_dcPlot
-     *  the will subsequently be BitBlt'd to the client in Paint
-     */
-    int currX, prevX, currY, prevY;
-    HPEN oldPen;
-    RECT rectCleanUp;
-    int i;
-
-    if (this->m_dcPlot != NULL)
+    if (inst->DrawSecondaryPlot)
     {
-        /*  shift the plot by BitBlt'ing it to itself
-         *  note: the m_dcPlot covers the entire client
-         *        but we only shift bitmap that is the size
-         *        of the plot rectangle
-         *  grab the right side of the plot (excluding m_nShiftPixels on the left)
-         *  move this grabbed bitmap to the left by m_nShiftPixels
-         */
-        BitBlt(this->m_dcPlot, this->m_rectPlot.left, this->m_rectPlot.top + 1,
-               this->m_nPlotWidth, this->m_nPlotHeight, this->m_dcPlot,
-               this->m_rectPlot.left+this->m_nShiftPixels, this->m_rectPlot.top
+ 1,
-               SRCCOPY);
-
-        /*  establish a rectangle over the right side of plot */
-        /*  which now needs to be cleaned up prior to adding the new point */
-        rectCleanUp = this->m_rectPlot;
-        rectCleanUp.left  = rectCleanUp.right - this->m_nShiftPixels;
-
-        /*  fill the cleanup area with the background */
-        FillRect(this->m_dcPlot, &rectCleanUp, this->m_brushBack);
-
-        /*  draw the next line segment */
-        for (i = 0; i < MAX_PLOTS; i++)
+        SelectObject(hdcg, inst->hPen1);
+        t = inst->PointBuffer + inst->NumberOfPoints;
+        x = inst->BitmapWidth - 1;
+        j = inst->CurrIndex;
+        y = h - *(t + j) * coef;
+        MoveToEx(hdcg, x, y, NULL);
+        for (i = 0; i < inst->NumberOfPoints; i++)
         {
-            /*  grab the plotting pen */
-            oldPen = (HPEN)SelectObject(this->m_dcPlot, this->m_penPlot[i]);
-
-            /*  move to the previous point */
-            prevX = this->m_rectPlot.right-this->m_nPlotShiftPixels;
-            prevY = this->m_rectPlot.bottom -
-                (long)((this->m_dPreviousPosition[i] - this->m_dLowerLimit) *
this->m_dVerticalFactor);
-            MoveToEx(this->m_dcPlot, prevX, prevY, NULL);
-
-            /*  draw to the current point */
-            currX = this->m_rectPlot.right-this->m_nHalfShiftPixels;
-            currY = this->m_rectPlot.bottom -
-                (long)((this->m_dCurrentPosition[i] - this->m_dLowerLimit) *
this->m_dVerticalFactor);
-            LineTo(this->m_dcPlot, currX, currY);
-
-            /*  Restore the pen  */
-            SelectObject(this->m_dcPlot, oldPen);
-
-            /*  if the data leaks over the upper or lower plot boundaries
-             *  fill the upper and lower leakage with the background
-             *  this will facilitate clipping on an as needed basis
-             *  as opposed to always calling IntersectClipRect
-             */
-            if ((prevY <= this->m_rectPlot.top) || (currY <=
this->m_rectPlot.top))
-            {
-                RECT rc;
-                rc.bottom = this->m_rectPlot.top + 1;
-                rc.left = prevX;
-                rc.right = currX + 1;
-                rc.top = this->m_rectClient.top;
-                FillRect(this->m_dcPlot, &rc, this->m_brushBack);
-            }
-            if ((prevY >= this->m_rectPlot.bottom) || (currY >=
this->m_rectPlot.bottom))
-            {
-                RECT rc;
-                rc.bottom = this->m_rectClient.bottom + 1;
-                rc.left = prevX;
-                rc.right = currX + 1;
-                rc.top = this->m_rectPlot.bottom + 1;
-                /* RECT rc(prevX, m_rectPlot.bottom+1, currX+1, m_rectClient.bottom+1);
*/
-                FillRect(this->m_dcPlot, &rc, this->m_brushBack);
-            }
-
-            /*  store the current point for connection to the next point */
-            this->m_dPreviousPosition[i] = this->m_dCurrentPosition[i];
+            j = (j ? j : inst->NumberOfPoints) - 1;
+            y = h - *(t + j) * coef;
+            x -= PLOT_SHIFT;
+            LineTo(hdcg, x, y);
         }
     }
-}
-void GraphCtrl_Resize(TGraphCtrl* this)
-{
-    /*  NOTE: Resize automatically gets called during the setup of the control */
-    GetClientRect(this->m_hWnd, &this->m_rectClient);
-
-    /*  set some member variables to avoid multiple function calls */
-    this->m_nClientHeight = this->m_rectClient.bottom -
this->m_rectClient.top;/* m_rectClient.Height(); */
-    this->m_nClientWidth  = this->m_rectClient.right -
this->m_rectClient.left;/* m_rectClient.Width(); */
-
-    /*  the "left" coordinate and "width" will be modified in  */
-    /*  InvalidateCtrl to be based on the width of the y axis scaling */
-#if 0
-    this->m_rectPlot.left   = 20;
-    this->m_rectPlot.top    = 10;
-    this->m_rectPlot.right  = this->m_rectClient.right-10;
-    this->m_rectPlot.bottom = this->m_rectClient.bottom-25;
-#else
-    this->m_rectPlot.left   = 0;
-    this->m_rectPlot.top    = -1;
-    this->m_rectPlot.right  = this->m_rectClient.right;
-    this->m_rectPlot.bottom = this->m_rectClient.bottom;
-#endif
-
-    /*  set some member variables to avoid multiple function calls */
-    this->m_nPlotHeight = this->m_rectPlot.bottom - this->m_rectPlot.top;/*
m_rectPlot.Height(); */
-    this->m_nPlotWidth  = this->m_rectPlot.right - this->m_rectPlot.left;/*
m_rectPlot.Width(); */
-
-    /*  set the scaling factor for now, this can be adjusted  */
-    /*  in the SetRange functions */
-    this->m_dVerticalFactor = (double)this->m_nPlotHeight / this->m_dRange;
+    SelectObject(hdcg, inst->hPen0);
+    t = inst->PointBuffer;
+    x = inst->BitmapWidth - 1;
+    j = inst->CurrIndex;
+    y = h - *(t + j) * coef;
+    MoveToEx(hdcg, x, y, NULL);
+
+    for (i = 0; i < inst->NumberOfPoints; i++)
+    {
+        j = (j ? j : inst->NumberOfPoints) - 1;
+        y = h - *(t + j) * coef;
+        x -= PLOT_SHIFT;
+        LineTo(hdcg, x, y);
+    }
 }
-#if 0
-void TGraphCtrl::Reset()
+inline void
+GraphCtrl_RedrawOnHeightChange(PTM_GRAPH_CONTROL inst, INT nh)
 {
-    /*  to clear the existing data (in the form of a bitmap) */
-    /*  simply invalidate the entire control */
-    InvalidateCtrl();
+    HDC     hdc;
+    HBITMAP hbmOld;
+
+    inst->BitmapHeight = nh;
+    inst->ftPixelsPerPercent = (FLOAT)nh / 100.00f;
+
+    hdc = GetDC(inst->hParentWnd);
+    hbmOld = inst->hbmGraph;
+    inst->hbmGraph = CreateCompatibleBitmap(hdc, inst->BitmapWidth, nh);
+    SelectObject(inst->hdcGraph, inst->hbmGraph);
+    DeleteObject(hbmOld);
+    ReleaseDC(inst->hParentWnd, hdc);
+
+    GraphCtrl_RedrawBitmap(inst, nh);
 }
-#endif
-extern TGraphCtrl PerformancePageCpuUsageHistoryGraph;
-extern TGraphCtrl PerformancePageMemUsageHistoryGraph;
+extern TM_GRAPH_CONTROL PerformancePageCpuUsageHistoryGraph;
+extern TM_GRAPH_CONTROL PerformancePageMemUsageHistoryGraph;
 extern HWND hPerformancePageCpuUsageHistoryGraph;
 extern HWND hPerformancePageMemUsageHistoryGraph;
 INT_PTR CALLBACK
 GraphCtrl_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
-    RECT        rcClient;
-    HDC            hdc;
-    PAINTSTRUCT     ps;
+    PTM_GRAPH_CONTROL graph;
     switch (message)
     {
@@ -652,27 +364,44 @@ GraphCtrl_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
         case WM_SIZE:
         {
-            if (hWnd == hPerformancePageMemUsageHistoryGraph)
-            {
-                GraphCtrl_Resize(&PerformancePageMemUsageHistoryGraph);
-                GraphCtrl_InvalidateCtrl(&PerformancePageMemUsageHistoryGraph, TRUE);
-            }
             if (hWnd == hPerformancePageCpuUsageHistoryGraph)
+                graph = &PerformancePageCpuUsageHistoryGraph;
+            else if (hWnd == hPerformancePageMemUsageHistoryGraph)
+                graph = &PerformancePageMemUsageHistoryGraph;
+            else
+                return 0;
+
+            if (HIWORD(lParam) != graph->BitmapHeight)
             {
-                GraphCtrl_Resize(&PerformancePageCpuUsageHistoryGraph);
-                GraphCtrl_InvalidateCtrl(&PerformancePageCpuUsageHistoryGraph, TRUE);
+                GraphCtrl_RedrawOnHeightChange(graph, HIWORD(lParam));
             }
+            InvalidateRect(hWnd, NULL, FALSE);
+
             return 0;
         }
         case WM_PAINT:
         {
+            RECT        rcClient;
+            HDC         hdc;
+            PAINTSTRUCT ps;
+
+            if (hWnd == hPerformancePageCpuUsageHistoryGraph)
+                graph = &PerformancePageCpuUsageHistoryGraph;
+            else if (hWnd == hPerformancePageMemUsageHistoryGraph)
+                graph = &PerformancePageMemUsageHistoryGraph;
+            else
+                return 0;
+
             hdc = BeginPaint(hWnd, &ps);
             GetClientRect(hWnd, &rcClient);
-            if (hWnd == hPerformancePageMemUsageHistoryGraph)
-                GraphCtrl_Paint(&PerformancePageMemUsageHistoryGraph, hWnd, hdc);
-            if (hWnd == hPerformancePageCpuUsageHistoryGraph)
-                GraphCtrl_Paint(&PerformancePageCpuUsageHistoryGraph, hWnd, hdc);
+            BitBlt(hdc, 0, 0,
+                   rcClient.right,
+                   rcClient.bottom,
+                   graph->hdcGraph,
+                   graph->BitmapWidth - rcClient.right,
+                   0,
+                   SRCCOPY);
             EndPaint(hWnd, &ps);
             return 0;
         }
diff --git a/base/applications/taskmgr/graphctl.h b/base/applications/taskmgr/graphctl.h
index 428d9c30b7d..5ea2aeaa82d 100644
--- a/base/applications/taskmgr/graphctl.h
+++ b/base/applications/taskmgr/graphctl.h
@@ -22,94 +22,62 @@
 #pragma once
-#define MAX_PLOTS 4
-#define MAX_CTRLS 4
+#define NUM_PLOTS    2
+#define PLOT_SHIFT   2
 #ifdef __cplusplus
 extern "C" {
 #endif
-#if 0
-/* Attributes */
-public:
-  void SetXUnits(const char* string);
-  void SetYUnits(const char* string);
-  /* Operations */
-public:
-  BOOL Create(DWORD dwStyle, const RECT& rect, HWND hParentWnd, UINT nID=NULL);
-
-#endif
-
-typedef struct
+typedef struct _TM_GRAPH_CONTROL
 {
-  int m_nShiftPixels;          /* amount to shift with each new point */
-  int m_nYDecimals;
-
-  char m_strXUnitsString[50];
-  char m_strYUnitsString[50];
-
-  COLORREF m_crBackColor;                 /* background color */
-  COLORREF m_crGridColor;                 /* grid color */
-  COLORREF m_crPlotColor[MAX_PLOTS];      /* data color   */
-
-  double m_dCurrentPosition[MAX_PLOTS];   /* current position */
-  double m_dPreviousPosition[MAX_PLOTS];  /* previous position */
-
-/* those were protected fields */
-  int m_nHalfShiftPixels;
-  int m_nPlotShiftPixels;
-  int m_nGridOffsetPixels;
-  int m_nClientHeight;
-  int m_nClientWidth;
-  int m_nPlotHeight;
-  int m_nPlotWidth;
-  int m_nGridXPixels;
-  int m_nGridYPixels;
-
-  double m_dLowerLimit;        /* lower bounds */
-  double m_dUpperLimit;        /* upper bounds */
-  double m_dRange;
-  double m_dVerticalFactor;
+    HWND     hParentWnd;
+    HWND     hWnd;
+    HDC      hdcGraph;
+    HBITMAP  hbmGraph;
+    HPEN     hPenGrid;
+    HPEN     hPen0;
+    HPEN     hPen1;
+    HBRUSH   hBrushBack;
+
+    INT      BitmapWidth;
+    INT      BitmapHeight;
+    INT      GridCellWidth;
+    INT      GridCellHeight;
+    INT      CurrShift;
+
+    PBYTE    PointBuffer;
+    UINT32   NumberOfPoints;
+    UINT32   CurrIndex;
+
+    FLOAT    ftPixelsPerPercent;
+    BOOL     DrawSecondaryPlot;
+}
+TM_GRAPH_CONTROL, *PTM_GRAPH_CONTROL;
-  HWND     m_hWnd;
-  HWND     m_hParentWnd;
-  HDC      m_dcGrid;
-  HDC      m_dcPlot;
-  HBITMAP  m_bitmapOldGrid;
-  HBITMAP  m_bitmapOldPlot;
-  HBITMAP  m_bitmapGrid;
-  HBITMAP  m_bitmapPlot;
-  HBRUSH   m_brushBack;
-  HPEN     m_penPlot[MAX_PLOTS];
-  RECT     m_rectClient;
-  RECT     m_rectPlot;
-} TGraphCtrl;
+typedef struct _TM_FORMAT
+{
+    COLORREF  clrBack;
+    COLORREF  clrGrid;
+    COLORREF  clrPlot0;
+    COLORREF  clrPlot1;
+    INT       GridCellWidth;
+    INT       GridCellHeight;
+    BOOL      DrawSecondaryPlot;
+}
+TM_FORMAT, *PTM_FORMAT;
 extern WNDPROC OldGraphCtrlWndProc;
-double  GraphCtrl_AppendPoint(TGraphCtrl* this,
-                              double dNewPoint0, double dNewPoint1,
-                              double dNewPoint2, double dNewPoint3);
-void    GraphCtrl_Create(TGraphCtrl* this, HWND hWnd, HWND hParentWnd,
-UINT nID);
-void    GraphCtrl_Dispose(TGraphCtrl* this);
-void    GraphCtrl_DrawPoint(TGraphCtrl* this);
-void    GraphCtrl_ShiftGrid(TGraphCtrl* this);
-void    GraphCtrl_InvalidateCtrl(TGraphCtrl* this, BOOL bResize);
-void    GraphCtrl_Paint(TGraphCtrl* this, HWND hWnd, HDC dc);
-void    GraphCtrl_Reset(TGraphCtrl* this);
-void    GraphCtrl_Resize(TGraphCtrl* this);
-void    GraphCtrl_SetBackgroundColor(TGraphCtrl* this, COLORREF
-color);
-void    GraphCtrl_SetGridColor(TGraphCtrl* this, COLORREF color);
-void    GraphCtrl_SetPlotColor(TGraphCtrl* this, int plot, COLORREF
-color);
-void    GraphCtrl_SetRange(TGraphCtrl* this, double dLower, double
-dUpper, int nDecimalPlaces);
-
 INT_PTR CALLBACK GraphCtrl_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam);
+BOOL GraphCtrl_Create(PTM_GRAPH_CONTROL inst, HWND hWnd, HWND hParentWnd, PTM_FORMAT
fmt);
+void GraphCtrl_Dispose(PTM_GRAPH_CONTROL inst);
+void GraphCtrl_AddPoint(PTM_GRAPH_CONTROL inst, BYTE val0, BYTE val1);
+void GraphCtrl_RedrawOnHeightChange(PTM_GRAPH_CONTROL inst, INT nh);
+void GraphCtrl_RedrawBitmap(PTM_GRAPH_CONTROL inst, INT h);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/base/applications/taskmgr/perfpage.c b/base/applications/taskmgr/perfpage.c
index eb021d2ae38..4bf550a8ff1 100644
--- a/base/applications/taskmgr/perfpage.c
+++ b/base/applications/taskmgr/perfpage.c
@@ -25,8 +25,8 @@
 extern BOOL bInMenuLoop;        /* Tells us if we are in the menu loop - from taskmgr.c
*/
-TGraphCtrl PerformancePageCpuUsageHistoryGraph;
-TGraphCtrl PerformancePageMemUsageHistoryGraph;
+TM_GRAPH_CONTROL PerformancePageCpuUsageHistoryGraph;
+TM_GRAPH_CONTROL PerformancePageMemUsageHistoryGraph;
 HWND  hPerformancePage;                               /*  Performance Property Page */
 HWND  hPerformancePageCpuUsageGraph;                  /*  CPU Usage Graph */
@@ -128,6 +128,9 @@ PerformancePageWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM
lParam)
         break;
     case WM_INITDIALOG:
+    {
+        BOOL bGraph;
+        TM_FORMAT fmt;
         /*  Save the width and height */
         GetClientRect(hDlg, &rc);
@@ -168,30 +171,30 @@ PerformancePageWndProc(HWND hDlg, UINT message, WPARAM wParam,
LPARAM lParam)
         hPerformancePageMemUsageHistoryGraph = GetDlgItem(hDlg,
IDC_MEM_USAGE_HISTORY_GRAPH);
         hPerformancePageCpuUsageHistoryGraph = GetDlgItem(hDlg,
IDC_CPU_USAGE_HISTORY_GRAPH);
-        GetClientRect(hPerformancePageCpuUsageHistoryGraph, &rc);
-        /*  create the control */
-        /* PerformancePageCpuUsageHistoryGraph.Create(0, rc, hDlg,
IDC_CPU_USAGE_HISTORY_GRAPH); */
-        GraphCtrl_Create(&PerformancePageCpuUsageHistoryGraph,
hPerformancePageCpuUsageHistoryGraph, hDlg, IDC_CPU_USAGE_HISTORY_GRAPH);
-        /*  customize the control */
-        GraphCtrl_SetRange(&PerformancePageCpuUsageHistoryGraph, 0.0, 100.0, 10);
-/*         PerformancePageCpuUsageHistoryGraph.SetYUnits("Current") ; */
-/*         PerformancePageCpuUsageHistoryGraph.SetXUnits("Samples (Windows Timer:
100 msec)") ; */
-/*         PerformancePageCpuUsageHistoryGraph.SetBackgroundColor(RGB(0, 0, 64)) ; */
-/*         PerformancePageCpuUsageHistoryGraph.SetGridColor(RGB(192, 192, 255)) ; */
-/*         PerformancePageCpuUsageHistoryGraph.SetPlotColor(RGB(255, 255, 255)) ; */
-        GraphCtrl_SetBackgroundColor(&PerformancePageCpuUsageHistoryGraph, RGB(0, 0,
0)) ;
-        GraphCtrl_SetGridColor(&PerformancePageCpuUsageHistoryGraph, RGB(0, 128,
64));
-
-        GraphCtrl_SetPlotColor(&PerformancePageCpuUsageHistoryGraph, 0, RGB(0, 255,
0)) ;
-        GraphCtrl_SetPlotColor(&PerformancePageCpuUsageHistoryGraph, 1, RGB(255, 0,
0)) ;
-
-
-        GetClientRect(hPerformancePageMemUsageHistoryGraph, &rc);
-        GraphCtrl_Create(&PerformancePageMemUsageHistoryGraph,
hPerformancePageMemUsageHistoryGraph, hDlg, IDC_MEM_USAGE_HISTORY_GRAPH);
-        GraphCtrl_SetRange(&PerformancePageMemUsageHistoryGraph, 0.0, 100.0, 10) ;
-        GraphCtrl_SetBackgroundColor(&PerformancePageMemUsageHistoryGraph, RGB(0, 0,
0)) ;
-        GraphCtrl_SetGridColor(&PerformancePageMemUsageHistoryGraph, RGB(0, 128, 64))
;
-        GraphCtrl_SetPlotColor(&PerformancePageMemUsageHistoryGraph, 0, RGB(255, 255,
0)) ;
+        /*  Create the controls */
+        fmt.clrBack = RGB(0, 0, 0);
+        fmt.clrGrid = RGB(0, 128, 64);
+        fmt.clrPlot0 = RGB(0, 255, 0);
+        fmt.clrPlot1 = RGB(255, 0, 0);
+        fmt.GridCellWidth = fmt.GridCellHeight = 12;
+        fmt.DrawSecondaryPlot = TaskManagerSettings.ShowKernelTimes;
+        bGraph = GraphCtrl_Create(&PerformancePageCpuUsageHistoryGraph,
hPerformancePageCpuUsageHistoryGraph, hDlg, &fmt);
+        if (!bGraph)
+        {
+            EndDialog(hDlg, 0);
+            return FALSE;
+        }
+
+        fmt.clrPlot0 = RGB(255, 255, 0);
+        fmt.clrPlot1 = RGB(100, 255, 255);
+        fmt.DrawSecondaryPlot = TRUE;
+        bGraph = GraphCtrl_Create(&PerformancePageMemUsageHistoryGraph,
hPerformancePageMemUsageHistoryGraph, hDlg, &fmt);
+        if (!bGraph)
+        {
+            EndDialog(hDlg, 0);
+            return FALSE;
+        }
+
         /*  Start our refresh thread */
 #ifdef RUN_PERF_PAGE
         hPerformanceThread = CreateThread(NULL, 0, PerformancePageRefreshThread, NULL, 0,
&dwPerformanceThread);
@@ -205,6 +208,7 @@ PerformancePageWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM
lParam)
         OldGraphCtrlWndProc =
(WNDPROC)SetWindowLongPtrW(hPerformancePageMemUsageHistoryGraph, GWLP_WNDPROC,
(LONG_PTR)GraphCtrl_WndProc);
         SetWindowLongPtrW(hPerformancePageCpuUsageHistoryGraph, GWLP_WNDPROC,
(LONG_PTR)GraphCtrl_WndProc);
         return TRUE;
+    }
     case WM_COMMAND:
         break;
@@ -447,16 +451,12 @@ DWORD WINAPI PerformancePageRefreshThread(void *lpParameter)
                 SendMessageW(hStatusWnd, SB_SETTEXT, 1, (LPARAM)Text);
             }
-            if (TaskManagerSettings.ShowKernelTimes)
-            {
-                CpuKernelUsage = PerfDataGetProcessorSystemUsage();
-                if (CpuKernelUsage <= 0)   CpuKernelUsage = 0;
-                if (CpuKernelUsage > 100) CpuKernelUsage = 100;
-            }
-            else
-            {
+            CpuKernelUsage = PerfDataGetProcessorSystemUsage();
+            if (CpuKernelUsage <= 0)
                 CpuKernelUsage = 0;
-            }
+            else if (CpuKernelUsage > 100)
+                CpuKernelUsage = 100;
+
             /*
              *  Get the memory usage
              */
@@ -468,9 +468,8 @@ DWORD WINAPI PerformancePageRefreshThread(void *lpParameter)
             PhysicalMemoryAvailable = PerfDataGetPhysicalMemoryAvailableK();
             nBarsUsed2 = PhysicalMemoryTotal ? ((PhysicalMemoryAvailable * 100) /
PhysicalMemoryTotal) : 0;
-            GraphCtrl_AppendPoint(&PerformancePageCpuUsageHistoryGraph, CpuUsage,
CpuKernelUsage, 0.0, 0.0);
-            GraphCtrl_AppendPoint(&PerformancePageMemUsageHistoryGraph, nBarsUsed1,
nBarsUsed2, 0.0, 0.0);
-            /* PerformancePageMemUsageHistoryGraph.SetRange(0.0, 100.0, 10) ; */
+            GraphCtrl_AddPoint(&PerformancePageCpuUsageHistoryGraph, CpuUsage,
CpuKernelUsage);
+            GraphCtrl_AddPoint(&PerformancePageMemUsageHistoryGraph, nBarsUsed1,
nBarsUsed2);
             InvalidateRect(hPerformancePageMemUsageHistoryGraph, NULL, FALSE);
             InvalidateRect(hPerformancePageCpuUsageHistoryGraph, NULL, FALSE);
         }
@@ -491,13 +490,16 @@ void PerformancePage_OnViewShowKernelTimes(void)
     {
         CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_UNCHECKED);
         TaskManagerSettings.ShowKernelTimes = FALSE;
+        PerformancePageCpuUsageHistoryGraph.DrawSecondaryPlot = FALSE;
     }
     else
     {
         CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_CHECKED);
         TaskManagerSettings.ShowKernelTimes = TRUE;
+        PerformancePageCpuUsageHistoryGraph.DrawSecondaryPlot = TRUE;
     }
+    GraphCtrl_RedrawBitmap(&PerformancePageCpuUsageHistoryGraph,
PerformancePageCpuUsageHistoryGraph.BitmapHeight);
     RefreshPerformancePage();
 }