|  | /* | 
|  | *  ReactOS Task Manager | 
|  | * | 
|  | *  graph.c | 
|  | * | 
|  | *  Copyright (C) 1999 - 2001  Brian Palmer  <brianp@reactos.org> | 
|  | *  Copyright (C) 2008  Vladimir Pankratov | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #define WIN32_LEAN_AND_MEAN    /* Exclude rarely-used stuff from Windows headers */ | 
|  | #include <windows.h> | 
|  | #include <commctrl.h> | 
|  | #include <stdlib.h> | 
|  | #include <memory.h> | 
|  | #include <stdio.h> | 
|  | #include <winnt.h> | 
|  |  | 
|  | #include "wine/unicode.h" | 
|  | #include "taskmgr.h" | 
|  | #include "perfdata.h" | 
|  |  | 
|  | #define BRIGHT_GREEN	RGB(0, 255, 0) | 
|  | #define DARK_GREEN	RGB(0, 130, 0) | 
|  | #define RED		RGB(255, 0, 0) | 
|  |  | 
|  |  | 
|  | WNDPROC             OldGraphWndProc; | 
|  |  | 
|  | static void Graph_DrawCpuUsageGraph(HDC hDC, HWND hWnd) | 
|  | { | 
|  | RECT            rcClient; | 
|  | RECT            rcBarLeft; | 
|  | RECT            rcBarRight; | 
|  | WCHAR            Text[256]; | 
|  | ULONG            CpuUsage; | 
|  | ULONG            CpuKernelUsage; | 
|  | int                nBars; | 
|  | int                nBarsUsed; | 
|  | /* Bottom bars that are "used", i.e. are bright green, representing used cpu time */ | 
|  | int                nBarsUsedKernel; | 
|  | /* Bottom bars that are "used", i.e. are bright green, representing used cpu kernel time */ | 
|  | int                nBarsFree; | 
|  | /* Top bars that are "unused", i.e. are dark green, representing free cpu time */ | 
|  | int                i; | 
|  |  | 
|  | static const WCHAR    wszFormatI[] = {'%','d','%','%',0}; | 
|  | static const WCHAR    wszFormatII[] = {' ',' ','%','d','%','%',0}; | 
|  | static const WCHAR    wszFormatIII[] = {' ','%','d','%','%',0}; | 
|  |  | 
|  | /* | 
|  | * Get the client area rectangle | 
|  | */ | 
|  | GetClientRect(hWnd, &rcClient); | 
|  |  | 
|  | /* | 
|  | * Fill it with blackness | 
|  | */ | 
|  | FillSolidRect(hDC, &rcClient, RGB(0, 0, 0)); | 
|  |  | 
|  | /* | 
|  | * Get the CPU usage | 
|  | */ | 
|  | CpuUsage = PerfDataGetProcessorUsage(); | 
|  | CpuKernelUsage = PerfDataGetProcessorSystemUsage(); | 
|  |  | 
|  | /* | 
|  | * Check and see how many digits it will take | 
|  | * so we get the indentation right every time. | 
|  | */ | 
|  | if (CpuUsage == 100) | 
|  | { | 
|  | sprintfW(Text, wszFormatI, (int)CpuUsage); | 
|  | } | 
|  | else if (CpuUsage < 10) | 
|  | { | 
|  | sprintfW(Text, wszFormatII, (int)CpuUsage); | 
|  | } | 
|  | else | 
|  | { | 
|  | sprintfW(Text, wszFormatIII, (int)CpuUsage); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Draw the font text onto the graph | 
|  | * The bottom 20 pixels are reserved for the text | 
|  | */ | 
|  | Font_DrawText(hDC, Text, ((rcClient.right - rcClient.left) - 32) / 2, rcClient.bottom - 11 - 5); | 
|  |  | 
|  | /* | 
|  | * Now we have to draw the graph | 
|  | * So first find out how many bars we can fit | 
|  | */ | 
|  | nBars = ((rcClient.bottom - rcClient.top) - 25) / 3; | 
|  | nBarsUsed = (nBars * CpuUsage) / 100; | 
|  | if ((CpuUsage) && (nBarsUsed == 0)) | 
|  | { | 
|  | nBarsUsed = 1; | 
|  | } | 
|  | nBarsFree = nBars - nBarsUsed; | 
|  | if (TaskManagerSettings.ShowKernelTimes) | 
|  | { | 
|  | nBarsUsedKernel = ((nBars * 2) * CpuKernelUsage) / 100; | 
|  | nBarsUsed -= (nBarsUsedKernel / 2); | 
|  | } | 
|  | else | 
|  | { | 
|  | nBarsUsedKernel = 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Now draw the bar graph | 
|  | */ | 
|  | rcBarLeft.left =  ((rcClient.right - rcClient.left) - 33) / 2; | 
|  | rcBarLeft.right =  rcBarLeft.left + 16; | 
|  | rcBarRight.left = rcBarLeft.left + 17; | 
|  | rcBarRight.right = rcBarLeft.right + 17; | 
|  | rcBarLeft.top = rcBarRight.top = 5; | 
|  | rcBarLeft.bottom = rcBarRight.bottom = 7; | 
|  |  | 
|  | if (nBarsUsed < 0)     nBarsUsed = 0; | 
|  | if (nBarsUsed > nBars) nBarsUsed = nBars; | 
|  |  | 
|  | if (nBarsFree < 0)     nBarsFree = 0; | 
|  | if (nBarsFree > nBars) nBarsFree = nBars; | 
|  |  | 
|  | if (nBarsUsedKernel < 0)     nBarsUsedKernel = 0; | 
|  | if (nBarsUsedKernel > nBars) nBarsUsedKernel = nBars; | 
|  |  | 
|  | /* | 
|  | * Draw the "free" bars | 
|  | */ | 
|  | for (i=0; i<nBarsFree; i++) | 
|  | { | 
|  | FillSolidRect(hDC, &rcBarLeft, DARK_GREEN); | 
|  | FillSolidRect(hDC, &rcBarRight, DARK_GREEN); | 
|  |  | 
|  | rcBarLeft.top += 3; | 
|  | rcBarLeft.bottom += 3; | 
|  |  | 
|  | rcBarRight.top += 3; | 
|  | rcBarRight.bottom += 3; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Draw the "used" bars | 
|  | */ | 
|  | for (i=0; i<nBarsUsed; i++) | 
|  | { | 
|  | if (nBarsUsed > 5000) nBarsUsed = 5000; | 
|  |  | 
|  | FillSolidRect(hDC, &rcBarLeft, BRIGHT_GREEN); | 
|  | FillSolidRect(hDC, &rcBarRight, BRIGHT_GREEN); | 
|  |  | 
|  | rcBarLeft.top += 3; | 
|  | rcBarLeft.bottom += 3; | 
|  |  | 
|  | rcBarRight.top += 3; | 
|  | rcBarRight.bottom += 3; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Draw the "used" kernel bars | 
|  | */ | 
|  | rcBarLeft.bottom--; | 
|  | rcBarRight.bottom--; | 
|  | if (nBarsUsedKernel && nBarsUsedKernel % 2) | 
|  | { | 
|  | rcBarLeft.top -= 2; | 
|  | rcBarLeft.bottom -= 2; | 
|  |  | 
|  | rcBarRight.top -= 2; | 
|  | rcBarRight.bottom -= 2; | 
|  |  | 
|  | FillSolidRect(hDC, &rcBarLeft, RED); | 
|  | FillSolidRect(hDC, &rcBarRight, RED); | 
|  |  | 
|  | rcBarLeft.top += 2; | 
|  | rcBarLeft.bottom += 2; | 
|  |  | 
|  | rcBarRight.top += 2; | 
|  | rcBarRight.bottom += 2; | 
|  |  | 
|  | nBarsUsedKernel--; | 
|  | } | 
|  | for (i=0; i<nBarsUsedKernel; i++) | 
|  | { | 
|  | if (nBarsUsedKernel > 5000) nBarsUsedKernel = 5000; | 
|  |  | 
|  | FillSolidRect(hDC, &rcBarLeft, RED); | 
|  | FillSolidRect(hDC, &rcBarRight, RED); | 
|  |  | 
|  | rcBarLeft.top++; | 
|  | rcBarLeft.bottom++; | 
|  |  | 
|  | rcBarRight.top++; | 
|  | rcBarRight.bottom++; | 
|  |  | 
|  | if (i % 2) | 
|  | { | 
|  | rcBarLeft.top++; | 
|  | rcBarLeft.bottom++; | 
|  |  | 
|  | rcBarRight.top++; | 
|  | rcBarRight.bottom++; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void Graph_DrawMemUsageGraph(HDC hDC, HWND hWnd) | 
|  | { | 
|  | RECT            rcClient; | 
|  | RECT            rcBarLeft; | 
|  | RECT            rcBarRight; | 
|  | WCHAR            Text[256]; | 
|  | ULONGLONG        CommitChargeTotal; | 
|  | ULONGLONG        CommitChargeLimit; | 
|  | int                nBars; | 
|  | int                nBarsUsed = 0; | 
|  | /* Bottom bars that are "used", i.e. are bright green, representing used memory */ | 
|  | int                nBarsFree; | 
|  | /* Top bars that are "unused", i.e. are dark green, representing free memory */ | 
|  | int                i; | 
|  |  | 
|  | static const WCHAR    wszFormat[] = {'%','d','K',0}; | 
|  |  | 
|  | /* | 
|  | * Get the client area rectangle | 
|  | */ | 
|  | GetClientRect(hWnd, &rcClient); | 
|  |  | 
|  | /* | 
|  | * Fill it with blackness | 
|  | */ | 
|  | FillSolidRect(hDC, &rcClient, RGB(0, 0, 0)); | 
|  |  | 
|  | /* | 
|  | * Get the memory usage | 
|  | */ | 
|  | CommitChargeTotal = (ULONGLONG)PerfDataGetCommitChargeTotalK(); | 
|  | CommitChargeLimit = (ULONGLONG)PerfDataGetCommitChargeLimitK(); | 
|  |  | 
|  | sprintfW(Text, wszFormat, (int)CommitChargeTotal); | 
|  |  | 
|  | /* | 
|  | * Draw the font text onto the graph | 
|  | * The bottom 20 pixels are reserved for the text | 
|  | */ | 
|  | Font_DrawText(hDC, Text, ((rcClient.right - rcClient.left) - (strlenW(Text) * 8)) / 2, rcClient.bottom - 11 - 5); | 
|  |  | 
|  | /* | 
|  | * Now we have to draw the graph | 
|  | * So first find out how many bars we can fit | 
|  | */ | 
|  | nBars = ((rcClient.bottom - rcClient.top) - 25) / 3; | 
|  | if (CommitChargeLimit) | 
|  | nBarsUsed = (nBars * (int)((CommitChargeTotal * 100) / CommitChargeLimit)) / 100; | 
|  | nBarsFree = nBars - nBarsUsed; | 
|  |  | 
|  | if (nBarsUsed < 0)     nBarsUsed = 0; | 
|  | if (nBarsUsed > nBars) nBarsUsed = nBars; | 
|  |  | 
|  | if (nBarsFree < 0)     nBarsFree = 0; | 
|  | if (nBarsFree > nBars) nBarsFree = nBars; | 
|  |  | 
|  | /* | 
|  | * Now draw the bar graph | 
|  | */ | 
|  | rcBarLeft.left =  ((rcClient.right - rcClient.left) - 33) / 2; | 
|  | rcBarLeft.right =  rcBarLeft.left + 16; | 
|  | rcBarRight.left = rcBarLeft.left + 17; | 
|  | rcBarRight.right = rcBarLeft.right + 17; | 
|  | rcBarLeft.top = rcBarRight.top = 5; | 
|  | rcBarLeft.bottom = rcBarRight.bottom = 7; | 
|  |  | 
|  | /* | 
|  | * Draw the "free" bars | 
|  | */ | 
|  | for (i=0; i<nBarsFree; i++) | 
|  | { | 
|  | FillSolidRect(hDC, &rcBarLeft, DARK_GREEN); | 
|  | FillSolidRect(hDC, &rcBarRight, DARK_GREEN); | 
|  |  | 
|  | rcBarLeft.top += 3; | 
|  | rcBarLeft.bottom += 3; | 
|  |  | 
|  | rcBarRight.top += 3; | 
|  | rcBarRight.bottom += 3; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Draw the "used" bars | 
|  | */ | 
|  | for (i=0; i<nBarsUsed; i++) | 
|  | { | 
|  | FillSolidRect(hDC, &rcBarLeft, BRIGHT_GREEN); | 
|  | FillSolidRect(hDC, &rcBarRight, BRIGHT_GREEN); | 
|  |  | 
|  | rcBarLeft.top += 3; | 
|  | rcBarLeft.bottom += 3; | 
|  |  | 
|  | rcBarRight.top += 3; | 
|  | rcBarRight.bottom += 3; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void Graph_DrawMemUsageHistoryGraph(HDC hDC, HWND hWnd) | 
|  | { | 
|  | RECT            rcClient; | 
|  | int                i; | 
|  | static int        offset = 0; | 
|  |  | 
|  | if (offset++ >= 10) | 
|  | offset = 0; | 
|  |  | 
|  | /* | 
|  | * Get the client area rectangle | 
|  | */ | 
|  | GetClientRect(hWnd, &rcClient); | 
|  |  | 
|  | /* | 
|  | * Fill it with blackness | 
|  | */ | 
|  | FillSolidRect(hDC, &rcClient, RGB(0, 0, 0)); | 
|  |  | 
|  | /* | 
|  | * Draw the graph background | 
|  | * | 
|  | * Draw the horizontal bars | 
|  | */ | 
|  | for (i=0; i<rcClient.bottom; i++) | 
|  | { | 
|  | if ((i % 11) == 0) | 
|  | { | 
|  | /* FillSolidRect2(hDC, 0, i, rcClient.right, 1, DARK_GREEN);  */ | 
|  | } | 
|  | } | 
|  | /* | 
|  | * Draw the vertical bars | 
|  | */ | 
|  | for (i=11; i<rcClient.right + offset; i++) | 
|  | { | 
|  | if ((i % 11) == 0) | 
|  | { | 
|  | /* FillSolidRect2(hDC, i - offset, 0, 1, rcClient.bottom, DARK_GREEN);  */ | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Draw the memory usage | 
|  | */ | 
|  | for (i=rcClient.right; i>=0; i--) | 
|  | { | 
|  | } | 
|  | } | 
|  |  | 
|  | INT_PTR CALLBACK | 
|  | Graph_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | HDC                hdc; | 
|  | PAINTSTRUCT        ps; | 
|  | LONG            WindowId; | 
|  |  | 
|  | switch (message) | 
|  | { | 
|  | case WM_ERASEBKGND: | 
|  | return TRUE; | 
|  |  | 
|  | /* | 
|  | * Filter out mouse  & keyboard messages | 
|  | */ | 
|  | /* case WM_APPCOMMAND: */ | 
|  | case WM_CAPTURECHANGED: | 
|  | case WM_LBUTTONDBLCLK: | 
|  | case WM_LBUTTONDOWN: | 
|  | case WM_LBUTTONUP: | 
|  | case WM_MBUTTONDBLCLK: | 
|  | case WM_MBUTTONDOWN: | 
|  | case WM_MBUTTONUP: | 
|  | case WM_MOUSEACTIVATE: | 
|  | case WM_MOUSEHOVER: | 
|  | case WM_MOUSELEAVE: | 
|  | case WM_MOUSEMOVE: | 
|  | /* case WM_MOUSEWHEEL: */ | 
|  | case WM_NCHITTEST: | 
|  | case WM_NCLBUTTONDBLCLK: | 
|  | case WM_NCLBUTTONDOWN: | 
|  | case WM_NCLBUTTONUP: | 
|  | case WM_NCMBUTTONDBLCLK: | 
|  | case WM_NCMBUTTONDOWN: | 
|  | case WM_NCMBUTTONUP: | 
|  | /* case WM_NCMOUSEHOVER: */ | 
|  | /* case WM_NCMOUSELEAVE: */ | 
|  | case WM_NCMOUSEMOVE: | 
|  | case WM_NCRBUTTONDBLCLK: | 
|  | case WM_NCRBUTTONDOWN: | 
|  | case WM_NCRBUTTONUP: | 
|  | /* case WM_NCXBUTTONDBLCLK: */ | 
|  | /* case WM_NCXBUTTONDOWN: */ | 
|  | /* case WM_NCXBUTTONUP: */ | 
|  | case WM_RBUTTONDBLCLK: | 
|  | case WM_RBUTTONDOWN: | 
|  | case WM_RBUTTONUP: | 
|  | /* case WM_XBUTTONDBLCLK: */ | 
|  | /* case WM_XBUTTONDOWN: */ | 
|  | /* case WM_XBUTTONUP: */ | 
|  | case WM_ACTIVATE: | 
|  | case WM_CHAR: | 
|  | case WM_DEADCHAR: | 
|  | case WM_GETHOTKEY: | 
|  | case WM_HOTKEY: | 
|  | case WM_KEYDOWN: | 
|  | case WM_KEYUP: | 
|  | case WM_KILLFOCUS: | 
|  | case WM_SETFOCUS: | 
|  | case WM_SETHOTKEY: | 
|  | case WM_SYSCHAR: | 
|  | case WM_SYSDEADCHAR: | 
|  | case WM_SYSKEYDOWN: | 
|  | case WM_SYSKEYUP: | 
|  |  | 
|  | case WM_NCCALCSIZE: | 
|  | return 0; | 
|  |  | 
|  | case WM_PAINT: | 
|  |  | 
|  | hdc = BeginPaint(hWnd, &ps); | 
|  |  | 
|  | WindowId = GetWindowLongPtrW(hWnd, GWLP_ID); | 
|  |  | 
|  | switch (WindowId) | 
|  | { | 
|  | case IDC_CPU_USAGE_GRAPH: | 
|  | Graph_DrawCpuUsageGraph(hdc, hWnd); | 
|  | break; | 
|  | case IDC_MEM_USAGE_GRAPH: | 
|  | Graph_DrawMemUsageGraph(hdc, hWnd); | 
|  | break; | 
|  | case IDC_MEM_USAGE_HISTORY_GRAPH: | 
|  | Graph_DrawMemUsageHistoryGraph(hdc, hWnd); | 
|  | break; | 
|  | } | 
|  |  | 
|  | EndPaint(hWnd, &ps); | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | } | 
|  |  | 
|  | /* | 
|  | * We pass on all non-handled messages | 
|  | */ | 
|  | return CallWindowProcW(OldGraphWndProc, hWnd, message, wParam, lParam); | 
|  | } |